Django应该自己实现DB的on_delete规则吗?



我有一个Django 1.3应用程序,我使用South 0.7.3进行DB迁移。我有一个问题,当父实体被删除时,on_delete=models.SET_NULL规则似乎没有被触发,从而给了我一个来自底层DB的约束违反(这是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中,所以DB肯定不会对破坏的关系本身执行无效操作:

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

然后我阅读Django文档中的on_delete规则,其中声明(我的重点):

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

"emulates"部分向我暗示,Django试图自己实现on_delete行为,而不依赖底层DB自动将其作为事务的一部分执行,从而使South错误无关紧要。

我有一个戳在Django db/models/deletion.py源和基于实施SET()/SET_NULL() collect()肯定似乎是Django应该这样做,但是,如果我想删除一个AccessPeriod Django管理员,我得到约束违反的支付表ID还引用现在删除,即它看起来不像Django是调用SET_NULL() Payment.period关系的一部分调用accessPeriod.delete()

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

在我的具体情况下,我将这个bug追溯到models.py代码中内联的ModelAdmin声明,导致模型类被错误地实例化,on_delete行为的破坏是最明显的副作用。从我的提交消息:

修复了Django中无法正确执行级联删除的问题DB .

事实证明,不要在models.py的全局作用域中声明ModelAdmins,否则所有的关系都是非常重要的在所有模型之前计算不同模型之间的关系很多人都被遗漏了。真的不是那么强调

因此,在我的原始(破碎)代码中,我将在每个模型之后立即声明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中,以便在处理了所有模型声明之后,每个类的所有元类设置都会发生,然后所有关系又开始正常运行。

最新更新