如何在Django Admin中实现向特定用户组添加条目及字段级权限控制
Django 细粒度权限控制实现方案
前置说明
你对接LDAP后,只要使用django-auth-ldap等常规插件,会自动将LDAP预定义的组同步到Django原生的auth.Group表中,用户的组隶属关系也会同步更新,不需要额外做组映射,直接调用request.user.groups即可获取用户所属的所有LDAP组。
1. 实现行级权限(组专属/多组共享条目控制)
第一步:改造模型增加权限关联字段
给需要控制访问范围的模型增加多对多字段,存储可访问本条数据的用户组:
from django.db import models from django.contrib.auth.models import Group # 以你的Person模型为例 class Person(models.Model): name = models.CharField(max_length=100) address = models.CharField(max_length=200) # 新增权限控制字段,支持关联多个组实现多组共享 allowed_groups = models.ManyToManyField(Group, related_name="accessible_records") # 其他原有字段保持不变
执行makemigrations和migrate同步表结构。后续创建条目时,给allowed_groups添加对应组,即可实现专属条目仅对应组成员可见,添加多个组即可实现跨组共享。
第二步:视图层过滤查询结果
在视图中过滤只返回当前用户有权限访问的条目即可:
函数视图(FBV)示例
from django.contrib.auth.decorators import login_required @login_required def persons_view(request): # 获取当前用户所属的所有组 user_groups = request.user.groups.all() # 过滤有权限的条目,distinct避免多组共享的条目重复返回 person_list = Person.objects.filter(allowed_groups__in=user_groups).distinct() # 后续原有视图逻辑不变
类视图(CBV)示例
from django.contrib.auth.mixins import LoginRequiredMixin from django.views.generic import ListView class PersonListView(LoginRequiredMixin, ListView): model = Person def get_queryset(self): user_groups = self.request.user.groups.all() return super().get_queryset().filter(allowed_groups__in=user_groups).distinct()
2. 实现字段级权限控制
根据你的技术栈选择对应的实现方式即可:
场景1:前后端分离(DRF接口)
在序列化器中根据用户组过滤返回字段:
from rest_framework import serializers from .models import Person class PersonSerializer(serializers.ModelSerializer): class Meta: model = Person fields = ["id", "name", "address"] def to_representation(self, instance): data = super().to_representation(instance) current_user = self.context["request"].user # 组名和LDAP同步的组名保持一致即可 if not current_user.groups.filter(name="人事管理组").exists(): # 无权限则移除敏感字段 data.pop("address") return data
场景2:服务端渲染(模板页面)
先自定义模板过滤器判断用户组权限:
# 应用目录下新建 templatetags/perm_filters.py from django import template register = template.Library() @register.filter(name="has_group") def has_group(user, group_name): return user.groups.filter(name=group_name).exists()
模板中按需渲染字段:
{% load perm_filters %} {% for person in person_list %} <p>姓名:{{ person.name }}</p> {% if request.user|has_group:"人事管理组" %} <p>地址:{{ person.address }}</p> {% endif %} {% endfor %}
场景3:Admin后台字段控制
如果需要在Admin后台也实现字段权限控制,重写Admin类的对应方法即可:
from django.contrib import admin from .models import Person @admin.register(Person) class PersonAdmin(admin.ModelAdmin): # 控制可见字段 def get_fields(self, request, obj=None): fields = super().get_fields(request, obj) if not request.user.is_superuser and not request.user.groups.filter(name="人事管理组").exists(): fields.remove("address") return fields # 控制Admin列表可见条目,和前端视图保持一致 def get_queryset(self, request): qs = super().get_queryset(request) if request.user.is_superuser: return qs user_groups = request.user.groups.all() return qs.filter(allowed_groups__in=user_groups).distinct()
内容的提问来源于stack exchange,提问作者piah
相关产品推荐
相关产品推荐

