当前位置: 代码迷 >> python >> 如何删除django中级联的一对一相关模型?
  详细解决方案

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

热度:74   发布时间:2023-06-13 14:05:32.0

背景:

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

class PublishInfo(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)

其中图书和NewsPaper股票相同的模型PublishInfo作为OneToOneField ,这实际上是一种独特的外键。

现在,如果我删除一个PublishInfo对象,相关的BookNewspaper对象将被级联删除。


题:

但实际上,我想在删除BookNewspaper对象时删除PublishInfo对象级联。 这种方式是我可以打电话的方式。

在这种情况下,有什么好的方法可以在相反方向上自动级联删除吗? 而且,如果是,能否解释一下?

您将信号附加到您的模型,以便在删除BookNewspaper实例时调用它:

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()

通过覆盖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()

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

因此,很快我意识到三个列表字段和方法在将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

记得在它的元类中添加abstract = True

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

class Book(PublishInfoAttachedModel, 
           models.Model):
    pass

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

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