【问题标题】:Is Django supposed to implement DB on_delete rules itself?Django 是否应该自己实现 DB on_delete 规则?
【发布时间】:2011-07-11 13:04:15
【问题描述】:

我有一个 Django 1.3 应用程序,我使用 South 0.7.3 进行数据库迁移。我有一个问题,当父实体被删除时,on_delete=models.SET_NULL 规则似乎没有被触发,从而给了我来自底层数据库(即 Postgres 8.4)的约束违规。

实体定义的相关部分是:

class AccessPeriod:
    ....

class Payment:
    period = models.ForeignKey( 
        AccessPeriod, related_name = "payments", db_index = True,
        null = True, on_delete = models.SET_NULL )

经过一番挖掘,我发现 South 实际上并没有将 ON DELETE 子句插入到它为迁移生成的 SQL 中,因此数据库肯定不会对损坏的关系本身进行无效化:

http://south.aeracode.org/ticket/763

然后我阅读了关于 on_delete 规则的 Django 文档,其中指出(我的重点):

当一个 ForeignKey 引用的对象被删除时,Django 通过 默认 模拟 SQL 约束 ON DELETE CASCADE 的行为 并删除包含 ForeignKey 的对象。这种行为 可以通过指定 on_delete 参数来覆盖。

“模拟”部分向我建议,Django 尝试自己实现 on_delete 行为,并且不依赖底层数据库作为事务的一部分自动执行此操作,从而使 South 错误无关紧要。

我对 Django 源代码中的 db/models/deletion.py 进行了探讨,基于 SET() / SET_NULL()collect() 的实现,似乎 Django 应该自己执行此操作,但是,如果我尝试从 Django 管理员中删除一个 AccessPeriod,我在 Payments 表上遇到了它仍然引用的 ID 的约束违规,该 ID 现在已被删除,即 Django 似乎没有在 Payment.period 关系上调用 SET_NULL() 作为致电accessPeriod.delete()

我在这里做错了什么,或者误解了 Django 应该做什么?只是想避免自己手动破解数据库来插入 ON DELETE 规则,这感觉非常脆弱和可怕。

【问题讨论】:

  • 如果您从 postgres 失败时获得堆栈跟踪,也许这会知道哪里出错了。这可能是你忽略的东西。

标签: django orm constraints django-south


【解决方案1】:

在我的特定情况下,我将此错误追溯到我的 models.py 代码中内联的 ModelAdmin 声明,导致我的模型类被错误地实例化,其中 on_delete 行为损坏是最明显的副作用。从我的提交信息中:

修复了在 Django 中无法正确完成级联删除的问题 数据库。

事实证明,不在 models.py 中的全局范围内声明您的 ModelAdmins 非常重要,否则所有关系 在所有模型计算之前计算不同模型之间的 加载和很多他们被排除在外。真的不是那么强调 关于这个在 Django 文档中。

因此,在我的原始(损坏的)代码中,我将在其后立即声明每个模型的 ModelAdmin,例如:

class AccessPeriod( models.Model ):
    ....

class AccessPeriodAdmin( models.ModelAdmin ):
    ....

# This causes the metaclass setup for AccessPeriod to happen right now,
# and since related models for AccessPeriod are not all declared yet,
# relationship handling behaviour becomes broken for AccessPeriod
admin.site.register( AccessPeriod, AccessPeriodAdmin )

class Payment( models.Model ):
    ....

class PaymentAdmin( models.ModelAdmin ):
    ....

# Same effect on the Payment model here    
admin.site.register( Payment, PaymentAdmin )

解决方案是将所有 ModelAdmin 声明移出 myapp/models.py 并移入 myapp/admin.py 以便在处理完所有模型声明之后发生每个类的所有元类设置,然后所有关系再次开始正常运行.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-27
    • 2011-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-27
    • 1970-01-01
    相关资源
    最近更新 更多