为啥 Django 模型级联删除在现实世界中会失败?

Posted

技术标签:

【中文标题】为啥 Django 模型级联删除在现实世界中会失败?【英文标题】:Why would a Django model cascade delete fail in the real world?为什么 Django 模型级联删除在现实世界中会失败? 【发布时间】:2011-10-17 21:47:27 【问题描述】:

鉴于 Django 模型:

类 ContainerOwner(模型。模型): id = models.IntegerField() 类容器(模型。模型): 所有者 = 模型.ForeignKey(ContainerOwner)

如果您对“ContainerOwner”对象调用 .delete(),它将级联删除该“ContainerOwner”拥有的所有“Container”对象。

但我发现在我的现实生活中的 django 项目中,有时这种级联删除似乎失败了。它似乎偶尔发生,当系统处于高容量时。因此,在“ContainerOwner”被删除后,您最终会得到没有有效“ContainerOwner”的“Container”对象(这应该是不可能的,“Containers”总是有一个“ContainerOwner”。)

以前有没有人见过这种类型的故障并能解释它是如何发生的?应用程序或数据库服务器在进行级联删除的过程中,级联删除会被中途杀死吗?

根据回答反馈更新问题:

1) 我们在 mysql 中使用 myisam

2) 我们正在使用查询集删除来删除“ContainerOwner”对象的查询集

3) MySQL 后端

4) 我们有一个非常常见的操作,即一次性删除所有“ContainerOwner”对象的 Django 查询集,并且也应该删除它们的所有“Container”对象。这种情况每天会发生几十次,我们只是注意到这些孤立的“容器”对象会导致应用程序错误。看起来只有很小比例的删除失败了,比如 0.01% 的删除会导致一些孤儿。

【问题讨论】:

【参考方案1】:

如果不了解有关您的应用程序的更多详细信息,实际上不可能回答您的实际问题,例如:

    ContainerOwner.delete()Container.delete() 中有自定义逻辑吗? 您是否在 ContainerOwner 上的任何地方使用查询集的 delete? 您使用的是什么数据库?? 创建/更新/删除ContainerOwner/Container对象的一般使用模式

但最重要的是:

"Container" objects that have no valid "ContainerOwner" after the "ContainerOwner" has been deleted

这首先在数据库级别上是不可能的,除非您缺少外键约束或者您使用的数据库不支持 FK 约束(如 MySQL + MISAM)。如果是前者,你应该先解决这个问题。如果是后者,请考虑切换,具体取决于这对您的应用的实际重要性。

【讨论】:

感谢您提供指导性问题的帮助,我已将原始问题更新为底部的答案。【参考方案2】:

如果其他人在此期间添加了一个具有相同 ContainerOwner 的容器,而您在事务之外,它将无法删除。在这些情况下,您应该得到一个 IntegrityError。

此外,如果您有任何 django 之外的代码,并且还有其他冲突的数据库约束,那么这些将阻止级联删除。

尝试检查您的数据库日志,看看删除失败的原因。

【讨论】:

以上是关于为啥 Django 模型级联删除在现实世界中会失败?的主要内容,如果未能解决你的问题,请参考以下文章

Django级联删除反向外键

如何使用不会将删除级联到其子级的 ForeignKeys 创建 Django 模型?

如何阻止这种级联删除在 Django 中发生?

为啥我的模型的“on_delete=models.CASCADE”不生成级联外键约束?

为啥这个 Django 模型上的这个非常基本的查询会失败?

触发器级联为啥会失败