Python Django-什么是cascade的反向等价物?

Python Django-什么是cascade的反向等价物?,python,django,Python,Django,我正在写一个小的音乐数据库。学习SQL在我的过去有相当长的一段时间,我一直想尝试一下django。但有一件事我无法理解 现在,我的模型只有两个类,Album和Song。 歌曲有一个外键指向它所属的唱片集。现在,如果我删除那张专辑,由于层叠效应,所有属于它的歌曲都将被删除 相册在我的数据库中是虚拟的,文件系统上实际上只显示歌曲,并且相册是根据歌曲标签构建的,因此,如果没有更多指向它的歌曲,我只能知道相册不再存在(因为它们不再存在于文件系统中) 或者简言之,如何实现反向级联,也就是说,如果没有更多的

我正在写一个小的音乐数据库。学习SQL在我的过去有相当长的一段时间,我一直想尝试一下django。但有一件事我无法理解

现在,我的模型只有两个类,
Album
Song
歌曲
有一个外键指向它所属的唱片集。现在,如果我删除那张
专辑
,由于层叠效应,所有属于它的
歌曲都将被删除

相册在我的数据库中是虚拟的,文件系统上实际上只显示歌曲,并且相册是根据歌曲标签构建的,因此,如果没有更多指向它的歌曲,我只能知道相册不再存在(因为它们不再存在于文件系统中)

或者简言之,如何实现反向级联,也就是说,如果没有更多的歌曲指向唱片集,那么唱片集也应该被删除?

当一首歌曲被删除且没有更多歌曲时,您可以使用该信号删除唱片集

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)

我也遇到过类似的问题,最后我在相册中添加了一个计数器。如果计数为0且操作为delete(),则相册对象为delete()d


其他解决方案包括在歌曲模型中重载delete()方法,或使用post delete删除相册

Django 1.3将提供定制级联行为的能力[1],但据我所知,仍然没有办法自动实现您所描述的功能

最好的方法可能是为您的
Song
类编写
post\u delete
信号处理程序[2],该处理程序检查相关的
Album
是否有剩余的
Song
并在适当时将其删除。我相信
ForeignKey
值应该仍然存在于
实例
参数中,尽管
歌曲
已从数据库中删除。(如果没有,请尝试使用
pre_delete

或者,您可以覆盖
delete
方法[3],但根据您删除对象的方式,并不总是调用该方法

[1]

[2]


[3]

有一个非常微妙的实现点,我认为我应该补充到这个讨论中

假设我们有两个模型,其中一个通过外键引用另一个,如中所示:

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,它将尝试删除已删除的项

诀窍是,要正确实现反向级联,您需要异常处理:

def delete_reverse(sender, **kwargs):
    try:
        if kwargs['instance'].a:
            kwargs['instance'].a.delete()
    except:
        pass
这段代码将以任何方式工作。我希望它能帮助一些人