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

时间:2019-01-15 20:59:10

标签: python django python-3.x postgresql cascading-deletes

我正在使用Django,Python 3.7和PostgreSQL 9.5。我该如何标记我的模型,以便生成级联的外键约束?我目前在我的models.py文件中有此文件...

class ArticleStat(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, )

当我在管理控制台中运行make migrations my_project时,它会生成一个包含此文件的文件...

    migrations.CreateModel(
        name='ArticleStat',
        fields=[
            ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
            ...
            ('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='my_project.Article')),
        ],
    ),

但是,当我运行迁移(使用migrate my_project 0001)时,生成的外键不包含级联删除约束。这就是PostgreSQL中的描述...

"my_project_articlesta_article_id_a02a5add_fk_my_project" FOREIGN KEY (article_id) REFERENCES my_project_article(id) DEFERRABLE INITIALLY DEFERRED

我还能如何获取我的models.py文件以输出级联删除外键约束?

1 个答案:

答案 0 :(得分:5)

django documentation of ForeignKey django中所述,它只是模拟了这种行为,而不是将其推迟到数据库中。

  

Django会在DELETE CASCADE上模拟SQL约束的行为,并删除包含ForeignKey的对象。

因此,请回答您的问题:这是预期的行为,并且仍然会像在数据库级别上一样起作用。

  

我还能如何获取我的models.py文件以输出级联删除外键约束?

您不能这样做,因为django当前不支持此功能。但是,有一张讨论添加它的票证:https://code.djangoproject.com/ticket/21961


编辑以进一步说明如何在数据库级别执行此操作

虽然我强烈建议您让django为您处理,但可能有理由不这样做。

要选择退出数据库表创建或删除操作,可以在False的{​​{1}}类中将Options.managed设置为Meta。但是,这也意味着您现在有责任手动进行迁移,例如编写ArticleStat语句以定义包含外键约束的表(因此您现在可以完全控制它)。要考虑的另一个考虑因素是,您应该指示django在删除引用的CREATE TABLE对象时不再执行任何操作(因为数据库现在对此负责)。可以通过将Article设置为models.DO_NOTHING来确保这一点。

将您的on_delete放在一起看起来像这样:

ArticleStat

关于信号的评论促使我重新审视此问题并列出了要考虑的陷阱。

  • 选择退出也意味着退出Django信号。特别是,class ArticleStat(models.Model): article = models.ForeignKey(Article, on_delete=models.DO_NOTHING) class Meta: managed = False pre_delete将不再为级联对象触发。

  • ticket description所述,混合数据库级和Django级联不能很好地发挥作用。

      

    如果模型A使用CASCADE_DB引用了模型B,但是模型B   使用常规CASCADE引用模型C,删除A不会   一直到C。

话虽如此,我找不到任何明确的证据证明django为何以目前的方式进行处理。