好吧,以下是我已經解決的解決方案,但它遠沒有令人滿意。
我已經添加了一個抽象基類,我的所有車型:
class MyModel(models.Model):
class Meta:
abstract = True
def pre_delete_handler(self):
pass
信號處理程序捕獲任何pre_delete
事件這一模式的子類:
def pre_delete_handler(sender, instance, **kwargs):
if isinstance(instance, MyModel):
instance.pre_delete_handler()
models.signals.pre_delete.connect(pre_delete_handler)
在我的每一個車型,如果存在子記錄,我通過從pre_delete_handler
方法拋出異常來模擬任何「ON DELETE RESTRICT
」關係。
class RelatedRecordsExist(Exception): pass
class SomeModel(MyModel):
...
def pre_delete_handler(self):
if children.count():
raise RelatedRecordsExist("SomeModel has child records!")
這會在任何數據被修改之前中止刪除。
不幸的是,不可能更新pre_delete信號中的任何數據(例如模擬ON DELETE SET NULL
),因爲在發送信號之前,Django已經生成了要刪除的對象列表。 Django這樣做是爲了避免陷入循環引用,並阻止多次不必要地發送對象信號。
確保可以執行刪除現在是調用代碼的責任。爲了幫助這一點,每個模型都有一個prepare_delete()
方法,該方法通過self.related_set.clear()
或類似的照顧設置鍵NULL
的:
class MyModel(models.Model):
...
def prepare_delete(self):
pass
爲了避免改變太多的代碼在我views.py
和models.py
,該delete()
方法被重寫在MyModel
調用prepare_delete()
:
class MyModel(models.Model):
...
def delete(self):
self.prepare_delete()
super(MyModel, self).delete()
這意味着,通過預期明確obj.delete()
調用的任何刪除將工作,但如果刪除已經從級聯一個涉及d對象或通過queryset.delete()
完成,並且調用代碼未確保在必要時所有鏈接都被中斷,則pre_delete_handler
將引發異常。
最後,我添加了一個類似post_delete_handler
方法被調用的post_delete
信號,讓模型清理任何其它數據模型(比如刪除文件ImageField
秒)
class MyModel(models.Model):
...
def post_delete_handler(self):
pass
def post_delete_handler(sender, instance, **kwargs):
if isinstance(instance, MyModel):
instance.post_delete_handler()
models.signals.post_delete.connect(post_delete_handler)
我希望能夠幫助某人,並且可以將代碼重新轉換回更有用的東西,而不會有太多麻煩。
任何有關如何改善此問題的建議都非常值得歡迎。
+1 - 根據文檔,設置爲'ForeignKey的領域on_delete'也將在Django 2.0要求。 – whusterj 2016-03-29 15:04:06