Django模型字段可调用默认值失效问题求助
我完全懂你的困惑——明明单独调用generate_question_key()能生成不同的随机字符串,为什么迁移后所有Question实例的key字段全是同一个值?这其实是Django迁移系统的特定行为导致的,我来给你拆解清楚:
问题根源
当你通过AddField迁移给已有模型添加带默认值的字段时,Django需要为数据库里所有已存在的记录填充这个新字段的值。如果你的默认值是一个可调用函数,Django的处理逻辑是:
- 只调用一次这个函数,拿到返回值
- 把这个值批量赋值给所有现有记录的新字段
这是出于迁移效率的考虑——如果数据库里有成百上千条记录,为每条单独调用函数会拖慢迁移速度,所以Django选择一次性生成一个值批量填充。而你之前其他字段用这个方式正常,大概率是因为那些字段是在创建模型时就定义的,没有涉及到给已有记录批量填充的场景。
解决方案
根据你的需求,分两种情况处理:
情况1:希望现有实例也拥有唯一的key值
这需要分三步完成迁移:
第一步:添加允许为空的字段
修改模型中的key字段,暂时允许为空,不设置默认值:class Question(Model): # 其他字段保持不变 key = TextField(null=True)生成并运行迁移文件(此时新字段会被添加,所有现有记录的
key值为NULL):python manage.py makemigrations python manage.py migrate第二步:编写数据迁移,为现有实例生成唯一
key
生成一个空的数据迁移:python manage.py makemigrations screen --empty打开生成的迁移文件,修改
operations部分,遍历所有Question实例并赋值:# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import migrations from screen.models import generate_question_key def populate_question_keys(apps, schema_editor): # 通过apps获取当前迁移上下文的Question模型 Question = apps.get_model('screen', 'Question') for question in Question.objects.all(): question.key = generate_question_key() question.save(update_fields=['key']) class Migration(migrations.Migration): dependencies = [ ('screen', '替换成你刚才生成的迁移文件名'), # 比如0065_question_key ] operations = [ migrations.RunPython(populate_question_keys), ]运行这个数据迁移:
python manage.py migrate第三步:设置默认值并取消空值允许(可选)
修改模型,把默认值加回来,并设置null=False(如果业务不允许字段为空的话):class Question(Model): # 其他字段保持不变 key = TextField(default=generate_question_key, null=False)再次生成并运行迁移:
python manage.py makemigrations python manage.py migrate
情况2:现有实例可以共用同一个key值,仅新实例用新值
这种情况你的现有代码是正常的,只是要明确:迁移时的批量填充只会用一次函数返回值,之后新创建的Question实例每次调用save()时,都会正常触发可调用函数生成新的随机key。如果你能接受现有实例的key相同,就不需要做任何修改。
验证
完成操作后,你可以检查数据库:
- 情况1下,现有实例的
key都会变成唯一的随机字符串 - 无论哪种情况,新创建的
Question实例都会生成全新的key
内容的提问来源于stack exchange,提问作者Will

