Django - ManyToManyRelation中的级联删除

问题描述 投票:15回答:4

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

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删除所有相关的BlogEntrys?如果删除了“其他”端的对象,则默认似乎是将对象保持为多对多关系。任何方式这样做 - 最好不要覆盖BlogEntry.delete

django many-to-many cascading-deletes
4个回答
13
投票

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

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


9
投票

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

  • 模特作者:可以有几个条目
  • 模特入门:可以有几位作者

为此,我正在使用多对多关系。

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

使用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
投票

你可以使用custom model manager,但文档似乎表明它does do something like this already和我不记得这究竟是什么意思:

删除方法很方便地命名为delete()。此方法立即删除对象并且没有返回值。例:

e.delete()

您也可以批量删除对象。每个QuerySet都有一个delete()方法,该方法删除该QuerySet的所有成员。

例如,这将删除pub_date年份为2005的所有Entry对象:

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

请记住,只要有可能,这将完全在SQL中执行,因此在此过程中不一定会调用各个对象实例的delete()方法。如果您在模型类上提供了自定义delete()方法并希望确保调用它,则需要“手动”删除该模型的实例(例如,通过迭代QuerySet并调用delete()on每个对象单独)而不是使用QuerySet的批量delete()方法。

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

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

1
投票

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

be = BlogEntry.objects.get(id=1)
be.blogentryrevision_set.clear()
© www.soinside.com 2019 - 2024. All rights reserved.