2012-09-29 111 views
10

Django演示了如何设置或取消在文档中使用外键级联删除。Django级联删除反向外键

model = models.ForeignKey(MyModel, null = True, on_delete = models.SET_NULL) 

但是如果我们想要另一种方式来解决这个问题呢?如果我们想要删除fk模型导致删除此模型会怎么样?

感谢

回答

0

我不认为你正在寻找的特征是一个ORM或数据库的概念。您只想在删除某些内容时执行回调。

所以使用post_deletesignal并添加有回调处理

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

@receiver(post_delete, sender=MyModel) 
def my_post_delete_callback(sender, **kwargs): 
    #Sender is the model which when deleted should trigger this action 
    #Do stuff like delete other things you want to delete 
    #The object just deleted can be accessed as kwargs[instance] 
+0

这种策略是不可靠的,因为'delete()'方法发出'on_delete'信号,并且'delete()'方法[不保证被调用](https://docs.djangoproject.com/en/dev/topics/db/queries /#deletion-objects)“,只要有可能,这将纯粹在SQL中执行,因此单个对象实例的delete()方法在进程中不一定会被调用。如果你在模型类上提供了一个自定义的delete()方法......“ – claytond

8

有一个非常微妙的实现角度,我认为我应该加入讨论。

比方说,我们有两个型号,其中一个引用外键的另一种,如:

class A(models.Model): 
    x = models.IntegerField() 

class B(models.Model): 
    a = models.ForeignKey(A, null=True, blank=True) 

现在,如果我们删除一个的条目中,级联行为将导致参考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 

此代码将工作无论哪种方式。我希望它能帮助一些人。

+0

顺便说一下,这可能不会导致无限递归,是不是? – minmaxavg