我正在使用 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 文件输出级联删除外键约束?
Django 模拟 SQL 约束 ON DELETE CASCADE 的行为,并删除包含外键的对象。
所以回答你的问题:这是预期的行为,并且仍然会像你期望它在数据库级别上工作一样工作。
我怎样才能让我的 models.py 文件输出级联删除外键约束?
你不能,因为 django 目前不支持此功能。然而,有一张票正在讨论添加它:https://code.djangoproject.com/ticket/21961
虽然我强烈建议让 django 为你处理这个问题,但可能有理由不这样做。
要选择退出数据库表创建或删除操作,您可以将 False
的
Meta
类中的 Options.management设置为
ArticleStat
。然而,这也意味着您现在负责手动进行迁移,例如编写 CREATE TABLE
语句来定义包含外键约束的表(因此您现在可以完全控制)。另一个需要考虑的因素是,您应该指示 django 在删除引用的 Article
对象时不再执行任何操作(因为您的数据库现在负责该操作)。这可以通过将 on_delete
设置为 models.DO_NOTHING 来确保。
将您的
ArticleStat
放在一起现在看起来像这样:
class ArticleStat(models.Model):
article = models.ForeignKey(Article, on_delete=models.DO_NOTHING)
class Meta:
managed = False
选择退出也意味着选择退出 django 信号。特别是
pre_delete
和 post_delete
将不再因级联对象而被触发。如票证描述中所述混合数据库和django级联不会很好地协同工作。
如果模型A使用CASCADE_DB引用模型B,但是模型B 使用常规 CASCADE 引用模型 C,删除 A 不会 一直级联到 C。
话虽如此,我找不到任何明确的证据来证明 django 为何以目前的方式处理这个问题。
db_constraint=False
并在迁移中添加带有级联删除的外键约束。
例如。
class ArticleStat(models.Model):
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
db_constraint=False # <----
)
class Migration(migrations.Migration):
...
operations = [
migrations.CreateModel(
name="ArticleStat",
fields=[
(
"article",
models.ForeignKey(
blank=True,
db_constraint=False,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to="app.article",
),
),
],
options={
"abstract": False,
},
),
# Add foreign key constraint with cascade delete.
migrations.RunSQL(
sql=[
"ALTER TABLE app_articlestat ADD CONSTRAINT app_articlestat FOREIGN KEY (article_id) REFERENCES app_article (id) ON DELETE CASCADE;",
],
reverse_sql=[
"ALTER TABLE app_articlestat DROP CONSTRAINT app_articlestat_article_id;",
]
)
]