django - 为什么我不能在 Django 的同一迁移中为组分配新权限
问题描述
我正在尝试按照本教程Meta
添加新的迁移,我在permissions
字段中
添加了新权限。然后我创建了迁移并尝试修改此迁移以更新组权限。却开工DoesNotExist
了RunPython
。
from django.db import migrations
def assign_new_permission(apps, *args):
Permission = apps.get_model('auth.Permission')
Group = apps.get_model('auth.Group')
# __fake__.DoesNotExist: Permission matching query does not exist.
new_permission = Permission.objects.get(
codename='my_new_permissoin_code')
admins = Group.objects.get(name='Group name')
admins.permissions.add(new_permission)
class Migration(migrations.Migration):
dependencies = [
('my_app', '0066_some_migratoin'),
]
operations = [
migrations.AlterModelOptions(
name='my_model',
options={'permissions': (('my_new_permissoin_code',
'Permission name'),)},
),
migrations.RunPython(assign_new_permission)
]
解决方案
I think that your problem occurs because permissions are not actually created during or after an individual migration, but are triggered by a post-migrate signal which is sent after the python manage.py migrate
command completes successfully (see comments on the accepted answer here.)
There are a few ways around it:
Split it into two separate migrations (create permissions and then assign them) and run them with two separate
python manage.py migrate
commands:python manage.py migrate my_app 0066_create_permissions python manage.py migrate my_app 0067_assign_permissions
This allows the post-migrate signal to be emitted after 0066 is run to create the permissions.
Split it up into two steps inside one migration, but you'll have to manually create the permissions with a Python function and then assign them in another. You'll have to modify your
operations
to account for that. One benefit of this is that if want to, you can create a Python function or functions to reverse the migration as well, which isn't really possible for #3 or #4.Emit the post-migrate signal yourself during the migration. This is a good solution for cases where you need permissions from 3rd party apps (like django-guardian, as in my case) so that you can apply them in data migrations.
from django.apps import apps as django_apps def guardian_post_migrate_signal(apps, schema_editor): guardian_config = django_apps.get_app_config('guardian') models.signals.post_migrate.send( sender=guardian_config, app_config=guardian_config, verbosity=2, interactive=False, using=schema_editor.connection.alias, )
This is similar to #3, but a little easier. There are probably subtle ways in which it is better or worse, but I'm not sure of what they are. You can create a function which calls
django.contrib.auth.management.create_permissions
(credit to this post) and use it directly in your migration:from django.contrib.auth.management import create_permissions def create_perms(apps, schema_editor): for app_config in apps.get_app_configs(): app_config.models_module = True create_permissions(app_config, apps=apps, verbosity=0) app_config.models_module = None
Then your
operations
would look like:operations = [ migrations.AlterModelOptions( name='my_model', options={'permissions': (('my_new_permission_code', 'Permission name'),)}, ), migrations.RunPython(create_perms), migrations.RunPython(assign_perms) ]
Anyway, I hope that helps. Sorry for the information overload - I've had the same issue as you in the past and it's set me back a few days.
推荐阅读
- c# - 如何让消费者应用程序在 .net 核心中保持活力
- c# - 方法中返回 HttpStatus 代码返回 Task
- >
- php - 如何将此具有多个 ors 的查询转换为 eloquent 格式?
- c++ - 禁用 GCC 5.4.0 和 RelWithDebInfo 构建类型的编译器优化
- php - PHP:无法在网页的表格中显示 csv 文件的数据
- java - 如何使用任意类型的键为通用二叉搜索树验证定义通用值范围(包括开放范围)
- java - 方法打印不正确
- python - 在这种情况下,Python 如何避免无限递归?
- c# - 哪个是控制域的空字段的最佳方法
- ios - DispatchQueue.main 中的自动布局不起作用