Django 中外键的默认值 migrations.AddField
Default value for foreign key in Django migrations.AddField
使用migrations,我需要向模型添加一个新字段(外键)。我知道可以用:
migrations.AddField(
model_name='MyModel',
name='state',
field=models.ForeignKey(null=True, related_name='mymodel_state', to='msqa_common.MyModelState'),
),
但是,我不希望我的字段可以为空。相反,我想为它使用一个默认值,对应于名称为 "available" 的 MyModelState 的 id(id 值可能会在不同的机器上发生变化)。 table MyModelState 的 "available" 值是在之前的迁移脚本中插入到数据库中的,因此它确实存在。
我想我应该这样做:
migrations.AddField(
model_name='MyModel',
name='state',
field=models.ForeignKey(null=False, default=available_state_id, related_name='mymodel_state', to='msqa_common.MyModelState'),
),
我的问题:如何在迁移脚本中获取 available_state_id
?
你不能直接做。这样做的推荐方法是创建一个迁移以使用 null=True 添加它,然后添加一个使用 Python 或 SQL 的数据迁移来更新所有现有的指向 available_state_id
,然后第三次迁移将其更改为 null=False。
我刚遇到同样的问题,偶然发现了这个答案,所以我是这样做的:
operations = [
# We are forced to create the field as non-nullable before
# assigning each Car to a Brand
migrations.AddField(
model_name="car",
name="brand",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="model.Brand",
),
),
# assign_car_to_brand loops over all my Car objects and sets their
# "brand" field
migrations.RunPython(add_category_to_tags, do_nothing),
# Make the field non-nullable to force all future Car to have a Brand
migrations.AlterField(
model_name="car",
name="brand",
field=models.ForeignKey(
null=False,
on_delete=django.db.models.deletion.PROTECT,
to="model.Brand",
),
preserve_default=False
),
]
这里有一个比较完整的例子:
第一步
python manage.py makemigrations
,设置临时默认值None
第二步
将生成的迁移代码更改为以下样式
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
def set_default_author_to_blog(apps, schema_editor):
User = apps.get_model("auth", "User")
Blog = apps.get_model("blog", "Blog")
Blog.objects.update(author=User.objects.first())
def revert_set_default_autor_to_blog(apps, schema_editor):
Blog = apps.get_model("blog", "Blog")
Blog.objects.update(author=None)
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('blog', '0001_auto_20220425_1017'),
]
operations = [
migrations.AddField(
model_name='blog',
name='author',
field=models.ForeignKey(null=True, db_constraint=False, on_delete=django.db.models.deletion.PROTECT,
to='auth.user', verbose_name='Author')
),
migrations.RunPython(set_default_author_to_blog, reverse_code=revert_set_default_autor_to_blog),
migrations.AlterField(
model_name='blog',
name='author',
field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.PROTECT,
to='auth.user', verbose_name='Author')
),
]
第三步
python manage.py migrate
使用migrations,我需要向模型添加一个新字段(外键)。我知道可以用:
migrations.AddField(
model_name='MyModel',
name='state',
field=models.ForeignKey(null=True, related_name='mymodel_state', to='msqa_common.MyModelState'),
),
但是,我不希望我的字段可以为空。相反,我想为它使用一个默认值,对应于名称为 "available" 的 MyModelState 的 id(id 值可能会在不同的机器上发生变化)。 table MyModelState 的 "available" 值是在之前的迁移脚本中插入到数据库中的,因此它确实存在。
我想我应该这样做:
migrations.AddField(
model_name='MyModel',
name='state',
field=models.ForeignKey(null=False, default=available_state_id, related_name='mymodel_state', to='msqa_common.MyModelState'),
),
我的问题:如何在迁移脚本中获取 available_state_id
?
你不能直接做。这样做的推荐方法是创建一个迁移以使用 null=True 添加它,然后添加一个使用 Python 或 SQL 的数据迁移来更新所有现有的指向 available_state_id
,然后第三次迁移将其更改为 null=False。
我刚遇到同样的问题,偶然发现了这个答案,所以我是这样做的:
operations = [
# We are forced to create the field as non-nullable before
# assigning each Car to a Brand
migrations.AddField(
model_name="car",
name="brand",
field=models.ForeignKey(
null=True,
on_delete=django.db.models.deletion.PROTECT,
to="model.Brand",
),
),
# assign_car_to_brand loops over all my Car objects and sets their
# "brand" field
migrations.RunPython(add_category_to_tags, do_nothing),
# Make the field non-nullable to force all future Car to have a Brand
migrations.AlterField(
model_name="car",
name="brand",
field=models.ForeignKey(
null=False,
on_delete=django.db.models.deletion.PROTECT,
to="model.Brand",
),
preserve_default=False
),
]
这里有一个比较完整的例子:
第一步
python manage.py makemigrations
,设置临时默认值None
第二步
将生成的迁移代码更改为以下样式
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
def set_default_author_to_blog(apps, schema_editor):
User = apps.get_model("auth", "User")
Blog = apps.get_model("blog", "Blog")
Blog.objects.update(author=User.objects.first())
def revert_set_default_autor_to_blog(apps, schema_editor):
Blog = apps.get_model("blog", "Blog")
Blog.objects.update(author=None)
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('blog', '0001_auto_20220425_1017'),
]
operations = [
migrations.AddField(
model_name='blog',
name='author',
field=models.ForeignKey(null=True, db_constraint=False, on_delete=django.db.models.deletion.PROTECT,
to='auth.user', verbose_name='Author')
),
migrations.RunPython(set_default_author_to_blog, reverse_code=revert_set_default_autor_to_blog),
migrations.AlterField(
model_name='blog',
name='author',
field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.PROTECT,
to='auth.user', verbose_name='Author')
),
]
第三步
python manage.py migrate