2012-09-29 147 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