使用django-guardian实现django-admin的行级权限控制的方法

下面是使用django-guardian实现django-admin的行级权限控制的方法的完整攻略。

什么是django-guardian

django-guardian是一个用于Django的第三方插件,它提供一种简单的方式来将对象级别的访问控制系统嵌入到你的应用程序中。

django-guardian安装

您可以使用pip安装django-guardian:

pip install django-guardian

然后将guardian添加到INSTALLED_APPS中:

INSTALLED_APPS = [
    # ...
    'guardian',
    # ...
]

并且在MIDDLEWARE中添加GuardianMiddleware

MIDDLEWARE = [
    # ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'guardian.middleware.GuardianMiddleware',
    # ...
]

最后,在settings.py文件中添加以下设置:

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'guardian.backends.ObjectPermissionBackend',
]

创建一个自定义的guardian后台

创建一个模型后台(ModelAdmin)是创建一个新的admin后台的第一步,这为您提供了一个管理特定模型的界面。 您可以针对不同的模型创建几个后台界面。

from django.contrib import admin

from .models import Post

@admin.register(Post)
class PostModelAdmin(admin.ModelAdmin):
    list_display = ('title', 'body', 'created_at', 'updated_at')

将Guardian添加到admin

需要创建一个自定义的admin后台,即一个子类GuardedModelAdmin(位于guardian.admin中),并将其传递给模型注册装饰器:

from django.contrib import admin
from guardian.admin import GuardedModelAdmin

from .models import Post

@admin.register(Post)
class PostModelAdmin(GuardedModelAdmin):
    list_display = ('title', 'body', 'created_at', 'updated_at')

第一种示例:给创建的文章添加用户级别的权限控制

现在,我们将为创建的文章添加用户级别的权限控制:

1.首先,在models.py中,定义一个组:

from django.contrib.auth.models import Group

class Writer(Group):

    class Meta:
        verbose_name = "Writer"
        verbose_name_plural = "Writers"

2.现在,我们需要使用guardian将该组与我们的Post模型相关联:

from django.db import models
from django.conf import settings
from django.urls import reverse
from guardian.shortcuts import assign_perm

class Post(models.Model):
    title = models.CharField(max_length=255)
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post_detail', args=[str(self.id)])

class Writer(Group):

    class Meta:
        verbose_name = "Writer"
        verbose_name_plural = "Writers"

# 在Post模型类中添加如下代码
class Meta:
    permissions = (("can_view_post", "Can view post"),)

assign_perm("can_view_post", Writer.objects.get_or_create(name="nobody")[0])

3.现在,我们需要为我们的Writer组提供一个权限的表单:

# 在admin.py中的PostModelAdmin类中添加如下代码
from django.contrib.auth.models import Group
from django.forms import CheckboxSelectMultiple
from guardian.admin import GuardedModelAdmin

class GroupAdminForm(forms.ModelForm):
    class Meta:
        model = Group
        fields = '__all__'
        widgets = {
            'permissions': CheckboxSelectMultiple,
        }

    permissions = forms.MultipleChoiceField(
        choices=[],
        widget=CheckboxSelectMultiple,
        help_text=_('Permissions of the group')
    )

    def __init__(self, *args, **kwargs):
        super(GroupAdminForm, self).__init__(*args, **kwargs)

        choices = [(x.id, x.name) for x in Permission.objects.all().order_by('content_type__app_label', 'content_type__model', 'codename')]
        self.fields['permissions'].choices = choices

    def save(self, commit=True):
        group = super(GroupAdminForm, self).save(commit)

        if commit:
            perms = self.cleaned_data.get('permissions', [])
            permissions = Permission.objects.filter(pk__in=perms)
            group.permissions.set(permissions)

        return group

@admin.register(Writer)
class WriterAdmin(GuardedModelAdmin):
    form = GroupAdminForm

4.接下来,我们为GroupAdminForm类提供一个角色权限筛选器:

# 在admin.py中的GroupAdminForm类中添加如下代码
from django.contrib.auth.models import Permission

class PermissionFilter(SimpleListFilter):
    title = _('permissions')
    parameter_name = 'permissions'

    def lookups(self, request, model_admin):
        perms = Permission.objects.all().order_by('content_type__app_label', 'content_type__model', 'codename')
        choices = []
        for perm in perms:
            content_type = perm.content_type
            choice = (f'{content_type.app_label}.{content_type.model}.{perm.codename}', perm.name)
            if choice not in choices:
                choices.append(choice)
        return choices

    def queryset(self, request, queryset):
        if self.value():
            content_type, codename = self.value().rsplit('.', 1)
            queryset = queryset.filter(
                permissions__content_type__app_label=content_type,
                permissions__content_type__model=content_type,
                permissions__codename=codename
            )
        return queryset

5.最后,我们需要修改PostModelAdmin以允许我们通过角色权限过滤器过滤结果:

# 在admin.py中的PostModelAdmin类中添加如下代码
class PostModelAdmin(GuardedModelAdmin):
    list_display = ('title', 'body', 'created_at', 'updated_at')
    list_filter = ('author', PermissionFilter)

    def get_queryset(self, request):
        qs = super(PostModelAdmin, self).get_queryset(request)

        if request.user.has_perm('can_view_post'):
            writer = Writer.objects.filter(user=request.user).first()
            if writer:
                qs = qs.filter(author__in=writer.user_set.all())

        return qs

第二种示例:给文章添加文章标题级别的权限控制

这是一个稍微复杂一些的示例,我们将使用django-guardian为每个文章的所有标题添加行级别权限。这意味着每个给定用户只能查看其被授权的文章的一部分,而不能查看全文。例如,假设我们创建了一篇名为“ hello_world ”的文章,它的标题是“ Hello World ”,它是通过一个包含三个<h2>标记的HTML文本构成的:

<h2>Hello</h2>
<h2>World</h2>
<h2>Today</h2>

现在假设我们有两个用户,名为Alice和Bob,Alice有权查看"Hello",而Bob有权查看"World"和"Today"。在本例中,我们将使用将每篇文章标题拆分为单独的条目的机制来实现。

  1. 首先,我们需要在models.py中为标题创建一个单独的模型,并将其与文章关联:
from django.db import models
from django.conf import settings
from django.urls import reverse

class Post(models.Model):
    title = models.CharField(max_length=255)
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('post_detail', args=[str(self.id)])

class PostTitle(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='titles')
    title = models.CharField(max_length=255)

    def __str__(self):
        return self.title

    class Meta:
        verbose_name = "Post Title"
        verbose_name_plural = "Post Titles"

2.现在,我们需要为每个标题分配一个权限。假设文章标题post.titles.all()的结果为以下内容:

[<PostTitle: Hello>, <PostTitle: World>, <PostTitle: Today>]

我们将授予Alice访问"Hello"的权限和Bob访问注意任何一个标题的权限。为了将权限分配给各个用户,我们将使用以下代码:

from django.contrib.auth.models import User
from guardian.shortcuts import assign_perm

post = Post()
post.save()

titles = ['Hello', 'World', 'Today']
for title in titles:
    PostTitle.objects.create(post=post, title=title)

alice = User.objects.create(username='alice')
bob = User.objects.create(username='bob')

assign_perm('view_posttitle', alice, post.titles.all()[0])
for title in post.titles.all():
    assign_perm('view_posttitle', bob, title)

这将导致以下授权:

  • Alice可以看到"Hello",而Bob不能。
  • Bob可以查看所有标题,而Alice不能。

  • 现在,我们将修改PostTitleModelAdmin以隐藏每个区域的权限和添加我们的自定义列表视图:

from django.conf.urls import url
from django.contrib import admin
from django.urls import reverse
from django.utils.html import format_html
from guardian.admin import GuardedModelAdmin

from .models import Post, PostTitle

class PostTitleInline(admin.TabularInline):
    model = PostTitle
    extra = 1


@admin.register(Post)
class PostModelAdmin(GuardedModelAdmin):
    inlines = [PostTitleInline]
    list_display = ('title', 'created_at', 'updated_at')
    ordering = ['-created_at']

    def get_queryset(self, request):
        qs = super(PostModelAdmin, self).get_queryset(request)

        if request.user.has_perm('view_posttitle'):
            qs = qs.filter(titles__pk__in=request.user.get_objects_for_user('view_posttitle', klass=PostTitle).values_list('pk', flat=True))

        return qs


@admin.register(PostTitle)
class PostTitleModelAdmin(GuardedModelAdmin):
    list_display = ('post', 'title_link')
    list_filter = ('post',)
    search_fields = ('title',)
    ordering = ('post', 'id')

    def has_view_permission(self, request, obj=None):
        return False

    def get_urls(self):
        urls = super(PostTitleModelAdmin, self).get_urls()
        info = self.model._meta.app_label, self.model._meta.model_name
        my_urls = [
            url(r'^(?P<pk>\d+)/view/$', self.admin_site.admin_view(self.view_title), name='%s_%s_view' % info),
        ]
        return my_urls + urls

    def view_title(self, request, pk):
        title = self.get_object(request, pk)
        return admin.views.main.single_object_template_response(request, title, 'view_title.html')

    def title_link(self, obj):
        url = reverse('admin:%s_%s_view' % (self.model._meta.app_label, self.model._meta.model_name), args=[obj.pk])
        return format_html('<a href="{}">{}</a>', url, obj.title)
    title_link.admin_order_field = 'title'
    title_link.short_description = 'Title'
  1. 创建我们的自定义模板(view_title.html)以允许我们仅显示每个标题的一部分:
{% extends "admin/base_site.html" %}

{% block content_title %}
    {{ object.title|safe }}
{% endblock %}

{% block content %}
    {% for title in object.post.titles.all %}
        {% if title|has_perm:'view_posttitle' %}
            <h2>{{ title.title|safe }}</h2>
        {% endif %}
    {% endfor %}
{% endblock %}

现在,当我们单击每个标题时,我们将只能看到我们已授权的部分。

详细的攻略就是这样了,希望能对你有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:使用django-guardian实现django-admin的行级权限控制的方法 - Python技术站

(0)
上一篇 2023年5月16日
下一篇 2023年5月16日

相关文章

  • 整合django和bootstrap框架

    环境: python版本:2.7.8 django版本:1.7.1 bootstrap版本:3.3.0 首先github上面有两个开源的项目用来整合django和bootstrap. https://github.com/dyve/django-bootstrap-toolkit 对应的是bootstrap 2.0版本 https://github.com/…

    Django 2023年4月13日
    00
  • Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程

    下面是 Ubuntu 14.04+Django 1.7.1+Nginx+uWSGI 部署教程的完整攻略: 1. 安装必要的软件 在开始部署之前,需要确保你的服务器安装了以下的软件: Nginx:一个高性能的 Web 服务器,可以作为 Web 应用的反向代理服务器 Python 和 pip:Python 是我们使用 django 的必备环境,pip 是 Pyt…

    Django 2023年5月15日
    00
  • django高级应用(分页功能)

    django高级应用(分页功能) 1、原生分页应用 前端html代码 1 <!DOCTYPE html> 2 <html lang=”en”> 3 <head> 4 <meta charset=”UTF-8″> 5 <title>Title</title> 6 </head>…

    Django 2023年4月13日
    00
  • Python之Django自动实现html代码(下拉框,数据选择)

      #模板   class IndexForm(forms.Form):   # 模板,用户提交的name和这里的变量名一定要是一致的.否则不能获取数据   user = forms.CharField(min_length=6, error_messages={‘required’: ‘用户名不能为空’, ‘min_length’: ‘用户名长度不能小于6…

    Django 2023年4月13日
    00
  • Django启动报错:AttributeError: ‘str’ object has no attribute ‘decode’

    Exception in thread Thread-1: Traceback (most recent call last): File “/usr/local/lib/python3.7/threading.py”, line 917, in _bootstrap_inner self.run() File “/usr/local/lib/python3…

    Django 2023年4月11日
    00
  • 使用IIS部署Django项目

    1.  系统及软件版本:   Windows Server 2008 Standard, IIS 7.0,  Python3.6+Django 2.0.4 2 .  python安装wfastcgi模块:   pip install wfastcgi 3.  拷贝wfastcgi.py文件   安装成功后,打开python目录—>Lib—>sit…

    Django 2023年4月13日
    00
  • Django Model里的__str__以及Meta

    举个栗子,注释已经比较详细了   name = models.CharField(max_length=30,verbose_name=’标签名称’) #max_length=30里的30在mysql以前版本表示字节数,现在新版表示字符数,不论中文还是英文还是标点最多只能有30个       #这个verbose_name是增加页面时显示的名称 class …

    Django 2023年4月11日
    00
  • Django Admin后台管理系统是什么?如何使用?

    Django Admin后台管理系统是什么? Django是一个高级Web框架,提供了一系列组件和工具,帮助开发人员快速开发高质量的Web应用程序。 其中,Django Admin是Django框架的一个常用组件之一,提供了一个易于使用的后台管理系统,方便了用户管理数据和应用程序的操作。 简单来说,Django Admin后台管理系统就是一个Web应用程序的…

    2023年3月11日
    00
合作推广
合作推广
分享本页
返回顶部