我正在写一个小型音乐数据库。在我过去学习SQL已经有很长一段时间了,我总是想尝试一下django。但是有一件事我无法解决。
目前,我的模型只包含两个类Album
和Song
。
Song
有一个指向其所属相册的外键。现在,如果我删除Album
,则属于它的所有Song
s“将因级联效应而被删除。
相册在我的数据库中是虚拟的,只有歌曲实际上是在文件系统上显示的,并且相册是根据歌曲标签构建的,因此我只能知道如果没有更多的歌曲指向一个专辑就不存在了它(因为它们不再存在于文件系统中)。
或者简而言之,我怎样才能实现反向级联,也就是说,如果没有更多的歌曲指向专辑,那么该专辑也应该被删除?
答案 0 :(得分:4)
删除歌曲并且没有更多歌曲时,您可以使用pre-delete信号删除相册。
from yourapp.models import Album, Song
from django.db.models.signals import pre_delete
def delete_parent(sender, **kwargs):
# Here you check if there are remaining songs.
....
pre_delete.connect(delete_parent, sender=Song)
答案 1 :(得分:1)
我遇到了类似的问题,我最终在相册中添加了一个计数器。如果计数为0且操作为delete(),则相册对象为delete()d。
其他解决方案是在歌曲模型中重载delete()方法,或使用post-delete删除相册。
答案 2 :(得分:0)
Django 1.3将提供定制级联行为的能力[1],但据我所知,仍然没有办法实现你自动描述的内容。
可能最好的方法是为post_delete
类编写Song
信号处理程序[2],检查相关的Album
是否还有Song
个如果合适,删除它。尽管已从数据库中删除了ForeignKey
,但我认为instance
参数中仍应存在Song
值。 (如果没有,请尝试使用pre_delete
)
或者你可以覆盖delete
方法[3],但这并不总是被调用,具体取决于你删除对象的方式。
[1] http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.on_delete
[2] http://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.post_delete
[3] http://docs.djangoproject.com/en/dev/ref/models/instances/#django.db.models.Model.delete
答案 3 :(得分:0)
有一个非常微妙的实施点,我认为我应该加入这个讨论。
假设我们有两个模型,其中一个模型通过外键引用另一个模型,如:
class A(models.Model):
x = models.IntegerField()
class B(models.Model):
a = models.ForeignKey(A, null=True, blank=True)
现在,如果删除A的条目,级联行为也会导致B中的引用被删除。
到目前为止,这么好。现在我们想要扭转这种行为。人们提到的显而易见的方法是使用删除期间发出的信号,所以我们去:
def delete_reverse(sender, **kwargs):
if kwargs['instance'].a:
kwargs['instance'].a.delete()
post_delete.connect(delete_reverse, sender=B)
这似乎是完美的。它甚至有效!如果我们删除B条目,则相应的A也将被删除。
问题是这有一个循环行为导致异常:如果我们删除A的项目,由于默认的级联行为(我们想要保留),B的相应项目也将被删除,将导致调用delete_reverse,它会尝试删除已删除的项目!
诀窍是,你需要EXCEPTION HANDLING才能正确实现反向级联:
def delete_reverse(sender, **kwargs):
try:
if kwargs['instance'].a:
kwargs['instance'].a.delete()
except:
pass
此代码将以任何方式工作。我希望它可以帮助一些人。