好的,以下是我确定的解决方案,虽然还远远不能令人满意。
我为我的所有模型添加了一个抽象基类:
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() 显式调用的删除都将按预期工作,但如果删除已从相关对象级联或通过queryset.delete() 完成并且调用代码不能确保所有链接都已断开必要时,pre_delete_handler 将抛出异常。
最后,我为模型添加了一个类似的 post_delete_handler 方法,该方法在 post_delete 信号上被调用,并让模型清除任何其他数据(例如删除 ImageFields 的文件。)
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)
我希望这对某人有所帮助,并且可以将代码重新线程化为更有用的东西而不会带来太多麻烦。
我们非常欢迎任何有关如何改进这一点的建议。