问题描述
背景:
我在 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
对象,相关的Book
或Newspaper
对象将被级联删除。
题:
但实际上,我想在删除Book
或Newspaper
对象时删除PublishInfo
对象级联。
这种方式是我可以打电话的方式。
在这种情况下,有什么好的方法可以在相反方向上自动级联删除吗? 而且,如果是,能否解释一下?
1楼
您将信号附加到您的模型,以便在删除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()
2楼
通过覆盖save
和delete
方法的另一个直接解决方案:
与@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
更明显。