Django同一迁移中为组分配新权限时出现DoesNotExist错误
解决Django迁移中RunPython触发Permission.DoesNotExist的问题
嘿,这个坑我之前踩过!你遇到的__fake__.DoesNotExist错误,核心原因是Django的模型权限并不是在你的迁移步骤里直接创建的——它是在所有迁移执行完成后,通过post_migrate信号来生成的。所以当你在同一个迁移文件的RunPython操作里去获取刚添加的权限时,这个权限还没被创建出来呢!
下面给你两个靠谱的解决方案:
方案一:拆分迁移文件(推荐)
最稳妥的方式是把「添加权限」和「分配权限给组」分成两个独立的迁移:
- 先正常生成添加权限的迁移:
这会生成一个包含python manage.py makemigrationsAlterModelOptions的迁移文件,用来更新模型的权限配置。 - 生成一个空的迁移文件专门处理权限分配:
python manage.py makemigrations --empty your_app_name - 在这个空迁移里编写你的权限分配逻辑:
from django.db import migrations def assign_new_permission(apps, schema_editor): Permission = apps.get_model('auth.Permission') Group = apps.get_model('auth.Group') # 现在可以安全获取权限了,因为之前的迁移已经执行完,post_migrate已经创建了权限 new_permission = Permission.objects.get( codename='your_new_permission_codename', content_type__app_label='your_app_name', content_type__model='your_model_name' ) # 找到目标组并添加权限 target_group = Group.objects.get(name='Your Target Group') target_group.permissions.add(new_permission) class Migration(migrations.Migration): dependencies = [ # 依赖刚才生成的添加权限的迁移 ('your_app_name', '000X_add_new_permission'), ] operations = [ migrations.RunPython(assign_new_permission), ] - 最后执行迁移:
python manage.py migrate
方案二:在同一个迁移中手动创建权限
如果你一定要把逻辑放在同一个迁移里,那可以手动在RunPython之前创建权限,不依赖post_migrate信号:
from django.db import migrations def create_new_permission(apps, schema_editor): Permission = apps.get_model('auth.Permission') ContentType = apps.get_model('contenttypes.ContentType') # 获取对应模型的ContentType content_type = ContentType.objects.get( app_label='your_app_name', model='your_model_name' ) # 用get_or_create避免重复创建 new_permission, _ = Permission.objects.get_or_create( codename='your_new_permission_codename', name='Your New Permission Label', content_type=content_type, ) def assign_new_permission(apps, schema_editor): Permission = apps.get_model('auth.Permission') Group = apps.get_model('auth.Group') new_permission = Permission.objects.get( codename='your_new_permission_codename', content_type__app_label='your_app_name', content_type__model='your_model_name' ) target_group = Group.objects.get(name='Your Target Group') target_group.permissions.add(new_permission) class Migration(migrations.Migration): dependencies = [ ('your_app_name', '000X_previous_migration'), ] operations = [ # 先手动创建权限 migrations.RunPython(create_new_permission), # 再分配给组 migrations.RunPython(assign_new_permission), # 保留自动生成的AlterModelOptions步骤 migrations.AlterModelOptions( name='your_model_name', options={ 'permissions': [ # 这里是你新增的权限 ('your_new_permission_codename', 'Your New Permission Label'), # 其他原有权限... ], }, ), ]
关键注意事项
- 永远用
codename + content_type的组合来查询权限,避免不同模型的同名权限冲突。 - 用
get_or_create而不是get来创建权限,防止迁移重复执行时出错。 - 方案一更符合Django的迁移设计规范,推荐优先使用。
内容的提问来源于stack exchange,提问作者Danil
相关产品推荐
相关产品推荐

