Django - 多对多关系中的级联删除

时间:2010-10-14 20:18:27

标签: django many-to-many cascading-deletes

使用以下相关模型(一个博​​客条目可以有多个修订版):

class BlogEntryRevision(models.Model):
    revisionNumber = models.IntegerField()
    title = models.CharField(max_length = 120)
    text = models.TextField()
    [...]

class BlogEntry(models.Model):
    revisions = models.ManyToManyField(BlogEntryRevision)
    [...]

如何在删除相应的BlogEntryRevision时告诉Django删除所有相关的BlogEntry?如果删除了“其他”端的对象,则默认似乎是将对象保持为多对多关系。有没有办法做到这一点 - 最好不要覆盖BlogEntry.delete

4 个答案:

答案 0 :(得分:13)

我认为你误解了ManyToMany关系的本质。你谈到被删除的“相应的BlogEntry”。但是,ManyToMany的重点在于每个BlogEntryRevision都有多个与其相关的 BlogEntries。 (当然,每个BlogEntry都有多个BlogEntryRevisions,但你已经知道了。)

从您使用的名称,以及您希望删除级联功能的事实来看,我认为使用BlogEntryRevision到BlogEntry的标准ForeignKey会更好。只要您没有在该ForeignKey上设置null=True,删除就会被删除 - 当删除BlogEntry时,所有修订也都是。

答案 1 :(得分:10)

我今天有这个确切的用例:

  • 模特作者:可以有几个条目
  • 模型录入:可以有多位作者

为此,我使用了ManyToManyRelationship。

我的用例是:如果删除特定作者的最后一个条目,那么也应该删除该作者。

可以使用pre_delete signal

来实现解决方案
@receiver(pre_delete, sender=Entry)
def pre_delete_story(sender, instance, **kwargs):
    for author in instance.authors.all():
        if author.entries.count() == 1 and instance in author.entries.all():
            # instance is the only Entry authored by this Author, so delete it
            author.delete()

答案 2 :(得分:2)

您可以使用custom model manager,但文档似乎表明does do something like this already并且我无法回想起这意味着什么:

  

删除方法很方便   命名为delete()。这种方法   立即删除对象并具有   没有回报价值。例如:

e.delete()
     

您也可以删除对象   散装。每个QuerySet都有一个delete()   方法,删除所有成员   那个QuerySet。

     

例如,这会删除所有条目   pub_date年份为2005年的对象:

Entry.objects.filter(pub_date__year=2005).delete()
     

请记住,无论何时,这都会   可能,纯粹用SQL执行,   所以delete()方法   单个对象实例不会   必然会被称为   处理。如果您提供了自定义   模型类的delete()方法和   想要确保它被调用,你   将需要“手动”删除   该模型的实例(例如,通过   迭代QuerySet并调用   单独删除每个对象上的()   而不是使用批量删除()   QuerySet的方法。

     

当Django删除一个对象时,它   模拟SQL的行为   约束ON DELETE CASCADE - in   换句话说,任何具有的对象   指向对象的外键   被删除将被删除   它。例如:

b = Blog.objects.get(pk=1)
# This will delete the Blog and all of its Entry objects.
b.delete()

答案 3 :(得分:1)

只需使用clear()方法删除相关对象,因为Django使用直通模型来指定clear方法删除所有相关BlogEntryRevision

的关系
be = BlogEntry.objects.get(id=1)
be.blogentryrevision_set.clear()