2015-10-29 61 views
3

如何找到對特定Django模型實例的所有直接外鍵引用?如何查找對實例的所有Django外鍵引用

我想要刪除一條記錄,但我想保留所有引用它的子記錄,所以我試圖在刪除之前用另一條記錄「替換」舊記錄的引用。

This類似的問題引用了Collector類。我想:

obj_to_delete = MyModel.objects.get(id=blah) 
new_obj = MyModel.objects.get(id=blah2) 
collector = Collector(using='default') 
collector.collect([obj_to_delete]) 
for other_model, other_data in collector.field_updates.iteritems(): 
    for (other_field, _value), other_instances in other_data.iteritems(): 

     # Why is this necessary? 
     if other_field.rel.to is not type(first_obj): 
      continue 

     for other_instance in other_instances: 
      setattr(other_instance, other_field.name, new_obj) 
      other_instance.save() 

# All FK references should be gone, so this should be safe to delete. 
obj_to_delete.delete() 

然而,這似乎有兩個問題:

  1. 有時collector.field_updates包含模型和什麼都沒有做我的目標obj_to_delete場的參考。
  2. 我的最終obj_to_delete.delete()調用失敗,IntegrityErrors抱怨仍然引用它的剩餘記錄,未被收集器捕獲的記錄。

我在做什麼錯?

我只需要一種方法來查找所有FK引用到單個模型實例。我不需要像在Django的標準刪除視圖中使用的任何形式的依賴關係查找。

回答

1

您可以使用Django的反向外鍵支持。

說你有兩個型號,像這樣:

class Foo(models.Model): 
    name = models.CharField(max_length=10) 

class Bar(models.Model): 
    descr = models.CharField(max_length=100) 
    foo = models.ForeignKey(Foo) 

那麼你知道你可以做bar_instance.foo訪問Foo對象是關鍵。但是,您可以使用Foo實例上的反向外鍵來獲取指向它的所有Bar對象,例如foo.bar_set

2

個人而言,我認爲最好的選擇是避免級聯刪除。

用適當的Django選項在相關模型中聲明外鍵,例如

on_delete=models.SET_NULL 

應該就足夠了。

中借鑑@約瑟夫的回答樣本型號:

class Foo(models.Model): 
    name = models.CharField(max_length=10) 

class Bar(models.Model): 
    descr = models.CharField(max_length=100) 
    foo = models.ForeignKey(Foo, blank=True, null=True, on_delete=models.SET_NULL)) 

正如官方Django docs描述,在這裏您可以使用預定義的行爲和實驗:

  • SET_NULL:設置ForeignKey null;這隻有在空值爲 時纔可以。

  • SET_DEFAULT:將ForeignKey設置爲其默認值;默認爲 必須設置ForeignKey。

  • SET():將ForeignKey設置爲傳遞給SET()的值,或者傳入可調用的對象,調用它的結果。在大多數情況下,通過一個可調用的將是必要的,以避免在你的models.py導入的時間執行查詢:

from django.conf import settings 
from django.contrib.auth import get_user_model 
from django.db import models 

def get_sentinel_user(): 
    return get_user_model().objects.get_or_create(username='deleted')[0] 

class MyModel(models.Model): 
    user = models.ForeignKey(settings.AUTH_USER_MODEL, 
          on_delete=models.SET(get_sentinel_user)) 
  • DO_NOTHING:不採取任何行動。如果您的數據庫後端強制執行 參照完整性,將會導致IntegrityError,除非您手動將SQL ON DELETE約束添加到數據庫字段