好的,以下是我确定的解决方案,尽管它远非令人满意。
我为所有模型添加了一个抽象基类:
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)
在我的每个模型中,如果存在子记录,我会ON DELETE RESTRICT
通过从方法中抛出异常来模拟任何“”关系。pre_delete_handler
class RelatedRecordsExist(Exception): pass
class SomeModel(MyModel):
...
def pre_delete_handler(self):
if children.count():
raise RelatedRecordsExist("SomeModel has child records!")
这会在修改任何数据之前中止删除。
不幸的是,无法更新 pre_delete 信号中的任何数据(例如 emulate ON DELETE SET NULL
),因为在发送信号之前,Django 已经生成了要删除的对象列表。Django 这样做是为了避免卡在循环引用上,并防止不必要地多次向对象发出信号。
确保可以执行删除现在是调用代码的责任。为了帮助解决这个问题,每个模型都有一个prepare_delete()
方法来处理将键设置为NULL
viaself.related_set.clear()
或类似的方法:
class MyModel(models.Model):
...
def prepare_delete(self):
pass
views.py
为了避免在我的and中更改太多代码models.py
,该delete()
方法被覆盖MyModel
以调用prepare_delete()
:
class MyModel(models.Model):
...
def delete(self):
self.prepare_delete()
super(MyModel, self).delete()
这意味着任何显式调用 viaobj.delete()
的删除都将按预期工作,但如果删除已从相关对象级联或通过 a 完成,queryset.delete()
并且调用代码未确保所有链接在必要时断开,pre_delete_handler
则将抛出异常.
最后,我为模型添加了一个类似的post_delete_handler
方法,该方法在信号上被调用post_delete
并让模型清除任何其他数据(例如删除ImageField
s 的文件。)
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)
我希望这对某人有所帮助,并且可以将代码重新线程化回更有用的东西而不会带来太多麻烦。
任何关于如何改进这一点的建议都非常受欢迎。