Django:可以对应用设置权限吗?

3 投票
2 回答
7380 浏览
提问于 2025-04-18 11:41

在我的Django网站上,我有几个应用,每个应用都是为了特定的用户群体使用。假设我有两个用户组:A组和B组。我有两个应用:App1,它的地址以/app1开头,和App2,它的地址以/app2开头。我想把使用App1的权限分配给A组,把使用App2的权限分配给B组。B组的用户永远不能访问所有以/app1开头的地址,反之亦然。

我该怎么做呢?

2 个回答

7

根据这个回答

下面是一个代码示例,教你如何把一个应用里所有现有的权限添加到一个组里。比如说,如果你有两个应用App1和App2,想要自动创建两个组,分别叫做app1和app2,并且每个组里包含各自应用的模型权限,可以试试这个方法:

在App1的apps.py文件里:

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 %}

我花了一些时间才找到这个过程,所以如果能帮助到其他人就太好了:

祝你好运 ;) !

5

你可以这样做,但我不太推荐。

你应该在实现 App1App2 的视图上使用 user_passes_test() 或者 permission_required() 这些装饰器。

你可以通过添加类似下面的内容来实现:

def in_group_a(user):
    return user.groups.filter(name="Group A").exists()

def in_group_b(user):
    return user.groups.filter(name="Group B").exists()

@user_passes_test(in_group_a)
def app1_view(request):
    ...

@user_passes_test(in_group_b)
def app2_view(request):
    ...

为了达到你想要的效果(基于 URL 前缀的 单一 检查),你需要为每个应用创建一个单独的视图,并通过类似下面的 URL 模式来访问:

url(r'^app1/(?P<remaining_url>.*)$', 'app1.views.app1`)

然后你的视图需要像上面那样运行 user_passes_test(),并手动解析 remaining_url 参数,以确定接下来该做什么:

@user_passes_test(in_group_a)
def app1(request, remaining_url):
    # parse remaining_url and work out what to do

但这个解析和分发的操作正是 Django 中的 URL 配置(urlconf)所用的。

理论上,你可以创建另一个特定于应用的 URL 配置(不在你的主 urls.py 中引用),并手动使用它的 API 将 remaining_url 重新分发到一组视图。

撰写回答