Django模型通常可以很好地处理删除时的级联行为(在某种程度上,它适用于本地不支持它的数据库)。
然而,我正在努力寻找在不合适的地方覆盖这种行为的最好方法,例如在以下场景中:
以下是我所知道的实现这些目标的潜在方法:
delete()
方法。虽然这种方法是有效的,但是当通过QuerySet
删除记录时,它就会被绕过。此外,每个模型的delete()
都必须被覆盖,以确保Django的代码永远不会被调用,并且super()
不能被调用,因为它可能使用QuerySet
删除子对象。第一种选择似乎是唯一可行的,但它很丑陋,会把婴儿和洗手水一起扔掉,而且当添加新的模型/关系时,可能会丢失一些东西。
我是不是遗漏了什么?有什么建议吗?
发布于 2010-12-09 05:04:08
对于那些遇到这个问题的人,请注意,Django 1.3中现在有一个内置的解决方案。
请参阅文档django.db.models.ForeignKey.on_delete中的详细信息,感谢代码片段网站的编辑指出这一点。
最简单的场景就是在你的模型FK字段定义中添加:
on_delete=models.SET_NULL
发布于 2010-03-19 14:35:39
Django只模拟级联行为。
根据Django用户组中的discussion的说法,最合适的解决方案是:
删除时重复限制方案-在删除前手动执行obj.rel_set.clear() (对于每个相关模型)删除时重复限制方案-在obj.delete()之前手动检查is obj.rel_set
发布于 2010-04-01 10:24:29
好的,以下是我已经决定的解决方案,尽管它远不能令人满意。
我为我的所有模型添加了一个抽象基类:
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
中更改太多代码,在MyModel
上重写了delete()
方法以调用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
信号上调用的模型添加了一个类似的post_delete_handler
方法,并让模型清除任何其他数据(例如,删除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)
我希望这对某些人有帮助,并且代码可以被重新线程化成更有用的东西,而不会有太多麻烦。
任何关于如何改进这一点的建议都非常受欢迎。
https://stackoverflow.com/questions/2475249
复制相似问题