如何删除django级联的一对一相关模型?

Alf*_*ang 6 python django model-view-controller orm model

背景:

我在Django(1.8.5)中定义了以下模型:

class PubishInfo(models.Model):
    pass

class Book(models.Model):
    info = models.OneToOneField(
        PublishInfo, on_delete=models.CASCADE)

class Newspaper(models.Model):
    info = models.OneToOneField(
        PublishInfo, on_delete=models.CASCADE)
Run Code Online (Sandbox Code Playgroud)

其中图书和NewsPaper股票相同型号PublishInfoOneToOneField,这实际上是一种独特的外键.

现在,如果我删除一个PublishInfoObject,则使用级联删除相关BookNewspaper对象.


题:

但事实上,我想要删除的PublishInfo对象级联当我删除BookNewspaper对象.这种方式是我打电话的方式.

在这种情况下,有没有什么好方法可以自动级联删除反向?

ozg*_*gur 5

您将post_delete信号附加到模型,以便在删除Book或的实例时调用它Newspaper

from django.db.models.signals import post_delete
from django.dispatch import receiver

@receiver(post_delete, sender=Book)
def auto_delete_publish_info_with_book(sender, instance, **kwargs):
    instance.info.delete()

@receiver(post_delete, sender=Newspaper)
def auto_delete_publish_info_with_newpaper(sender, instance, **kwargs):
    instance.info.delete()
Run Code Online (Sandbox Code Playgroud)

  • 对于批量插入和删除,不会发送此类信号。所以,是的,我认为最便宜的方法是一一删除。此外,如果您希望批量更新具有相同的行为,您可能需要为模型创建子类化查询集类并覆盖“delete”方法。 (2认同)

Alf*_*ang 5

通过覆盖savedelete方法的另一个直接解决方案:

与@ozgur 的答案相比,我发现使用信号级联删除操作与通过覆盖Model.delete()方法删除的效果相同,而且我们可能会自动创建附加的PublishInfo

class Book(models.Model):

    info = models.OneToOneField(
        PublishInfo, on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if not self.info:
            self.info = Publish.objects.create()
            super().save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        super().delete(*args, **kwargs)
        if self.info:
            self.info.delete()
Run Code Online (Sandbox Code Playgroud)

更结构化和可重用的解决方案:

因此,很快我意识到三个列表字段和方法在将PublishInfo模型附加为字段的每个模型上显然是多余的。

那么,我们为什么不使用继承呢?

class PublishInfoAttachedModel(models.Model):

    info = models.OneToOneField(
        PublishInfo, related_name='$(class)s',
        on_delete=models.CASCADE)

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        if not self.info:
            self.info = Publish.objects.create()
            super().save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        super().delete(*args, **kwargs)
        if self.info:
            self.info.delete()

    class Meta:
        abstract = True
Run Code Online (Sandbox Code Playgroud)

记得添加abstract = True它的元类。

所以,现在我们可以自由地添加PublishInfo我们想要附加到该模型的任何其他模型,并且我们可以制作多个这样的抽象模型:

class Book(PublishInfoAttachedModel, 
           models.Model):
    pass

class NewsPaper(PublishInfoAttachedModel, 
           CommentsAttachedModel,  # if we have other attached model info
           models.Model):
    pass
Run Code Online (Sandbox Code Playgroud)

注意models.Model后面的超类列表中的类可以忽略,我写这只是为了使类更明显地作为Model.