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

Dav*_*ave 4 python django postgresql cascading-deletes python-3.x

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

class ArticleStat(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, )
Run Code Online (Sandbox Code Playgroud)

当我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')),
        ],
    ),
Run Code Online (Sandbox Code Playgroud)

但是,当我运行迁移(使用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
Run Code Online (Sandbox Code Playgroud)

我怎么能得到我的models.py文件输出级联删除外键约束?

Fyn*_*ker 5

正如django的django文档中ForeignKey所描述的那样只是模仿这种行为而不是将其推迟到数据库.

Django模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象.

所以回答你的问题:这是预期的行为,并且仍然会像你期望它在数据库级别上工作一样工作.

我怎么能得到我的models.py文件输出级联删除外键约束?

您不能因为django目前不支持此功能.但是有一张票要讨论添加它:https://code.djangoproject.com/ticket/21961


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

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

要选择退出数据库表中创建或删除操作,您可以设置Options.managedFalseMetaArticleStat.然而,这也意味着您现在负责手动执行迁移,例如编写CREATE TABLE语句以定义包含外键约束的表(因此您可以完全控制它).另一个需要考虑的因素是你应该指示django不再对删除引用的Article对象做任何事情(因为你的数据库现在对此负责).这可以通过设置模型on_delete来确保.DO_NOTHING.

放在一起你ArticleStat现在看起来像这样:

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

    class Meta:
        managed = False
Run Code Online (Sandbox Code Playgroud)

关于信号的评论促使我重新审视并列出了一些需要考虑的陷阱.

  • 选择退出意味着选择退出django信号.尤其是pre_deletepost_delete不会为级联的对象不再被解雇.

  • 正如票证说明中所提到的,混合数据库和django-cascading不能很好地融合在一起.

    如果模型A使用CASCADE_DB引用模型B,但模型B使用常规CASCADE引用模型C,则删除A将不会一直级联到C.

话虽如此,我找不到任何明确的证据,说明为什么django正在以当前的方式处理它.

  • 我想补充一点,Django在应用程序中实现级联删除的原因是支持模型删除信号(`pre_delete`和`post_delete`).如果使用与"DO_NOTHING"配对的数据库级别级联删除,则不会触发这些信号. (2认同)