【问题标题】:How to create groups and assign permission during project setup in django?如何在 django 项目设置期间创建组和分配权限?
【发布时间】:2017-03-12 04:38:12
【问题描述】:

我知道我可以从 django 项目的管理区域创建用户组并为其分配权限。我还可以通过从 django 的 auth 模块导入 GroupPermission 模型来创建一个组并为其分配权限。

我想知道在设置项目时是否有任何方法可以创建组并为他们分配权限。所以,如果我有用户类型,AdminDeveloperTesterProject Manager。它们基本上是具有不同权限级别的用户组。我没有自定义User 模型,只能通过分配给它们的组来区分。那么有没有办法创建这些组并为它们分配所需的权限,例如当我运行python manage.py migrate 时为管理员创建权限时?

【问题讨论】:

    标签: python django


    【解决方案1】:

    您可以定义一个post_migrate 信号来创建所需的UserGroup 模型实例(如果它们尚不存在)。

    当您使用python manage.py startapp <app_name> 创建应用程序时,它会在apps.py 文件中创建一个AppConfig 类。

    您可以在AppConfig 类定义中指定要调用的信号。假设该信号称为populate_models。在这种情况下,将 AppConfig 修改为如下所示:

    from django.apps import AppConfig
    from django.db.models.signals import post_migrate
    
    class AppConfig(AppConfig):
        name = 'app'
    
        def ready(self):
            from .signals import populate_models
            post_migrate.connect(populate_models, sender=self)
    

    在signals.py中定义populate_models函数。

    def populate_models(sender, **kwargs):
        from django.contrib.auth.models import User
        from django.contrib.auth.models import group
        # create groups
        # assign permissions to groups
        # create users
    

    【讨论】:

    • 那么这个信号是在初始迁移之后还是每次迁移之后发出的?我是否需要检查组和权限是否已经存在然后添加?
    • 是的,每次migrate 调用后都会发出信号。您必须检查一些UserGroup 是否已经存在。您可以使用get_or_create 快捷方式。
    • 或者您也可以检查User.objects.count() 是否为零。
    • 无法保证此post_migrate 处理程序将在django.contrib.auth 定义的创建权限的处理程序之后运行。因此,此代码可以运行,并且没有权限分配给组。
    • @PenguinBrian 你确定没有保证吗?这个解决方案对我有用。起初我认为它不起作用,但事实证明问题是我的函数在每个应用程序的每个 post_migrate 处理程序中运行(我使用的是@receiver 装饰器)。一旦我正确连接通过发件人,问题就解决了。如果 Django 以确定的方式决定调用处理程序的顺序,这应该总是有效的。你知道不是这样吗?顺序是不确定的吗?
    【解决方案2】:

    根据@narenda-choudhary 和@Rolando Cruz 的回答,

    这是在组下添加应用的所有现有权限的代码。 例如,如果您有 App1 和 App2,并且您想自动创建 2 个名为 app1 和 app2 的组,分别包含对每个应用程序模型的权限,请尝试以下操作:

    对于apps.py 上的App1:

    from django.apps import AppConfig
    from django.db.models.signals import post_migrate
    
    class App1Config(AppConfig):
        name = 'app1'
    
        def ready(self):
            from .signals import populate_models
            post_migrate.connect(populate_models, sender=self)
    

    创建一个包含以下内容的 signals.py 文件:

    def populate_models(sender, **kwargs):
        from django.apps import apps
        from .apps import App1Config
        from django.contrib.auth.models import Group, Permission
        from django.contrib.contenttypes.models import ContentType
    
        group_app, created = Group.objects.get_or_create(name=App1Config.name)
    
        models = apps.all_models[App1Config.name]
        for model in models:
            content_type = ContentType.objects.get(
                app_label=App1Config.name,
                model=model
            )
            permissions = Permission.objects.filter(content_type=content_type)
            group_app.permissions.add(*permissions)
    

    对 App2 执行相同操作

    然后将用户分配到他们的组。

    用法:

    在每个应用程序上创建一个名为 permissions.py 的文件并添加:

    from .apps import App1Config
    
    def is_in_group_app1(user):
        return user.groups.filter(name=App1Config.name).exists() 
    

    在views.py中使用:

    from django.contrib.auth.decorators import login_required, user_passes_test
    from .permissions import is_in_group_app1
    
    @login_required(login_url='where_to_redirect')
    @user_passes_test(is_in_group_app1) 
    def myview(request):
        # Do your processing
    

    对于 CBV:

    @method_decorator(user_passes_test(is_in_group_app1), name='dispatch')
    class LogListView(ListView):
        """ Displays all logs saved on App1 """
        model= Logger.objects.order_by('-date_created')
    

    创建一个名为 templatestag 的文件夹和子文件夹 app1 和一个 has_perms.py 文件:

    from django import template
    from app1.permissions import is_in_group_app1
    register = template.Library()
    
    @register.filter
    def has_perms(user):
        return is_in_group_app1(user)
    

    在您的模板中:

    {% load has_perms %}
    
    {% if request.user|has_perms %}
        <li class="nav-item">
            <a href="{% url 'app1:log' %}" class="nav-link">
                <i class="icon-history"></i>
                <span data-i18n="nav.dash.main">App1 Log</span>
            </a>
        </li>
    {% endif %}
    

    我花了一段时间才找到所有这些过程,所以如果它可以帮助其他人:

    享受 ;) !

    【讨论】:

      【解决方案3】:

      注意:向下滚动查看我的代码实现。

      Django 至少在以下方面自动填充数据库:

      查看源码(django.contrib.contenttypesdjango.contrib.authdjango.contrib.sites),发现如下模式:

      • 将接收函数连接到AppConfig内的post_migrate信号。

        来自django.contrib.sites.apps的示例:

        class SitesConfig(AppConfig):
            ...
        
            def ready(self):
                post_migrate.connect(create_default_site, sender=self)
                ...
        
      • management模块中定义receiver函数(而不是在signal模块内部,通常用于定义信号本身),并使用apps.get_model()获取模型类(而不是直接导入模型可能与当前迁移状态不一致的类)。

        来自django.contrib.sites.management的示例:

        def create_default_site(app_config, verbosity=2, interactive=True, using=DEFAULT_DB_ALIAS, apps=global_apps, **kwargs):
            try:
                Site = apps.get_model('sites', 'Site')
            except LookupError:
                return
        
            if not router.allow_migrate_model(using, Site):
                return
        
            if not Site.objects.using(using).exists():
                ...
        

        这里最重要的参数是apps,用于获取处于当前迁移状态的模型。如果您使用multiple databases,您还需要using 参数来检查是否允许迁移模型并在查询的.using() 中使用该模型。其他参数说明请查看post_migrate signal docs

      谈话很便宜。给我看代码!

      • 我创建了一个assign_group_permissions() 函数,它返回一个接收器函数,该函数填充给定组的一些权限。

        someproject/accounts/management.py:

        from django import apps as global_apps
        from django.db.models import Q
        
        
        def assign_group_permissions(group_name, permissions):
            def receiver(*args, apps=global_apps, **kwargs):
                try:
                    Group = apps.get_model('auth', 'Group')
                    Permission = apps.get_model('auth', 'Permission')
                except LookupError:
                    return
        
                perm_q = Q()
                for perm in permissions:
                    app_label, codename = perm.split('.')
                    perm_q |= Q(content_type__app_label=app_label) & Q(codename=codename)
        
                group, _ = Group.objects.get_or_create(name=group_name)
                group.permissions.add(
                    *Permission.objects.filter(perm_q)
                )
        
            return receiver
        
      • 在每个对应的AppConfig 内调用函数。下面的示例展示了如何将 Announcement 模型的查看、添加、更改和删除权限分配给 event_admin 组,该模型位于 someproject.announcements 应用程序中。

        someproject/announcements/apps.py:

        from django.apps import AppConfig
        from django.db.models.signals import post_migrate
        
        from someproject.accounts.management import assign_group_permissions
        
        
        class AnnouncementConfig(AppConfig):
            name = 'someproject.announcements'
        
            def ready(self):
                post_migrate.connect(assign_group_permissions(
                    'event_admin',
                    [
                        'announcements.add_announcement',
                        'announcements.change_announcement',
                        'announcements.delete_announcement',
                        'announcements.view_announcement',
                    ],
                ))
        

      【讨论】:

        猜你喜欢
        • 2013-11-20
        • 2013-09-18
        • 1970-01-01
        • 1970-01-01
        • 2017-10-23
        • 1970-01-01
        • 2014-10-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多