Django 1.7 程序化添加组代码放在哪里?
我一直在查找Django认证文档里的答案,但找不到我想要的内容。
我遇到的问题是,当我定义添加组的代码(和管理员页面里的组一样)时:
#read_only
group, created = Group.objects.get_or_create(name='read_only')
if created:
group.permissions.add(can_read_campaign)
logger.info('read_only_user Group created')
#standard
group, created = Group.objects.get_or_create(name='standard_user')
if created:
group.permissions.add(can_edit_users)
logger.info('standard_user Group created')
#admin
group, created = Group.objects.get_or_create(name='admin_user')
if created:
group.permissions.add(can_edit_campaign, can_edit_users)
logger.info('admin_user Group created')
我在models.py和init.py中运行这段代码,结果都给我报了这个错:
django.core.exceptions.AppRegistryNotReady
我猜这可能是因为Model/init试图在Django的应用程序/管理界面中太早插入东西?
我该如何以编程方式添加这些组呢?
编辑:
这不是重复的问题,这实际上是在项目设置过程中在模型中添加权限和组,而不是通过命令行。
我通过使用信号和接收器(Django模块)解决了这个问题。
我把创建权限/组的代码放到一个单独的函数里,并用一个接收器(post_migrate)装饰它,这样在迁移完成后就会运行这个函数,从而消除了这个错误。
@receiver(post_migrate)
def init_groups(sender, **kwargs):
#permission and group code goes here
3 个回答
5
@Ruloweb的精彩回答差不多能解决我的问题,但我需要做一些调整才能在Django 3.1中与多个应用一起使用。
首先,我需要给add_group_permissions()这个函数添加一些参数。此外,我还需要导入emit_post_migration_signal:
from django.contrib.auth.models import Group, Permission
from django.core.management.sql import emit_post_migrate_signal # <-- Added this
from django.db import models, migrations
import logging
logger = logging.getLogger(__name__)
public_group_permissions = {
"Your permission group name here": ['your permissions here']
}
def add_group_permissions(apps, schema_editor): # <-- updated this
# See https://code.djangoproject.com/ticket/23422
db_alias = schema_editor.connection.alias
try:
emit_post_migrate_signal(2, False, 'default')
except TypeError: # Django < 1.8
emit_post_migrate_signal([], 2, False, 'default', db_alias)
for group in public_group_permissions:
role, created = Group.objects.get_or_create(name=group)
logger.info(f'{group} Group created')
for perm in public_group_permissions[group]:
role.permissions.add(Permission.objects.get(codename=perm))
logger.info(f'Permitting {group} to {perm}')
role.save()
class Migration(migrations.Migration):
dependencies = [
('your_app_name', '0001_initial'),
]
operations = [
migrations.RunPython(add_group_permissions),
]
5
结合@Robert Grant和这个链接,我成功地做到了:
python manage.py makemigrations --empty yourappname
然后:
from django.contrib.auth.models import Group, Permission
from django.db import models, migrations
import logging
logger = logging.getLogger(__name__)
campaign_group_permissions = {
"Campaign Manager": [
"add_campaign",
"change_campaign",
"delete_campaign",
"view_campaign",
"add_campaignsms",
"add_sending",
"change_sending",
"view_sending"
]
}
def add_group_permissions():
# See https://code.djangoproject.com/ticket/23422
db_alias = schema_editor.connection.alias
try:
emit_post_migrate_signal(2, False, 'default')
except TypeError: # Django < 1.8
emit_post_migrate_signal([], 2, False, 'default', db_alias)
for group in campaign_group_permissions:
role, created = Group.objects.get_or_create(name=group)
logger.info(f'{group} Group created')
for perm in campaign_group_permissions[group]:
role.permissions.add(Permission.objects.get(codename=perm))
logger.info(f'Permitting {group} to {perm}')
role.save()
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunPython(add_group_permissions),
]
注意:这个方法适用于Django 3.x,但我相信它在Django 1.7上也能用。
31
我被推荐使用这种方法来处理这个问题:
首先,在合适的模块里创建一个假的迁移文件:
python manage.py makemigrations --empty yourappname
然后打开刚创建的文件,内容应该像这样:
# -*- coding: utf-8 -*-
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
]
接下来,添加你的代码:
# -*- coding: utf-8 -*-
from django.db import models, migrations
def add_group_permissions():
#read_only
group, created = Group.objects.get_or_create(name='read_only')
if created:
group.permissions.add(can_read_campaign)
logger.info('read_only_user Group created')
#standard
group, created = Group.objects.get_or_create(name='standard_user')
if created:
group.permissions.add(can_edit_users)
logger.info('standard_user Group created')
#admin
group, created = Group.objects.get_or_create(name='admin_user')
if created:
group.permissions.add(can_edit_campaign, can_edit_users)
logger.info('admin_user Group created')
class Migration(migrations.Migration):
dependencies = [
('yourappname', '0001_initial'),
]
operations = [
migrations.RunPython(add_group_permissions),
]
最后,运行这个迁移:
python manage.py migrate
这样做的好处是,你可以把它部署到Heroku或者其他地方,并且可以确保这个迁移会被应用,因为它只是另一个迁移而已。