Django 1.7 程序化添加组代码放在哪里?

17 投票
3 回答
7912 浏览
提问于 2025-04-18 15:15

我一直在查找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或者其他地方,并且可以确保这个迁移会被应用,因为它只是另一个迁移而已。

撰写回答