Django多级别权限认证定制指导请求(新手开发者)
Django四级权限认证系统实现指导
一、模型层优化
1. 确保用户唯一关联职位
每个用户只能归属一个权限级别,需给UserPositions添加唯一约束,避免同一用户多条职位记录:
class UserPositions(models.Model): # ... 现有字段定义 class Meta: constraints = [ models.UniqueConstraint(fields=['user'], name='unique_user_position') ]
2. 职位关联字段合法性校验
不同职位对应的外键(省份/培训中心)需符合逻辑,重写clean方法做前置校验:
def clean(self): super().clean() if self.position == self.Position.CENTRAL_OFFICE: if self.province or self.center: raise ValidationError(_("中央办公室用户无需关联省份或培训中心")) elif self.position == self.Position.PROVINCE: if not self.province or self.center: raise ValidationError(_("省级用户必须关联省份,且不能关联培训中心")) elif self.position == self.Position.TRAINING_CENTER: if not self.center: raise ValidationError(_("培训中心用户必须关联培训中心")) # 自动同步培训中心所属省份,避免数据不一致 self.province = self.center.province elif self.position == self.Position.UNIVERSITY_STUDENT: if self.province or self.center: raise ValidationError(_("大学生用户无需关联省份或培训中心"))
二、权限校验实现
1. 自定义视图装饰器(针对FBV)
用于快速校验用户是否属于指定权限级别:
from django.http import HttpResponseForbidden def require_position(*allowed_positions): def decorator(view_func): def wrapped_view(request, *args, **kwargs): try: user_position = request.user.userpositions_set.get() except UserPositions.DoesNotExist: return HttpResponseForbidden("未分配权限级别") if user_position.position not in allowed_positions: return HttpResponseForbidden("权限不足") # 将职位信息附加到request,方便视图内直接使用 request.user_position = user_position return view_func(request, *args, **kwargs) return wrapped_view return decorator
使用示例:
@require_position(UserPositions.Position.CENTRAL_OFFICE, UserPositions.Position.PROVINCE) def province_dashboard(request): # 视图逻辑:仅中央/省级用户可访问 pass
2. 类视图权限Mixin(针对CBV)
适配Django类视图的权限控制,继承后指定允许的职位即可:
from django.contrib.auth.mixins import AccessMixin from django.http import HttpResponseForbidden class PositionRequiredMixin(AccessMixin): allowed_positions = [] # 子类需定义允许的权限级别 def dispatch(self, request, *args, **kwargs): try: user_position = request.user.userpositions_set.get() except UserPositions.DoesNotExist: return HttpResponseForbidden("未分配权限级别") if user_position.position not in self.allowed_positions: return HttpResponseForbidden("权限不足") request.user_position = user_position return super().dispatch(request, *args, **kwargs)
使用示例:
class CenterListView(PositionRequiredMixin, ListView): allowed_positions = [ UserPositions.Position.TRAINING_CENTER, UserPositions.Position.PROVINCE, UserPositions.Position.CENTRAL_OFFICE ] model = Center # ... 其他视图配置
3. 精细化数据权限控制
实现用户只能访问所属层级的数据(比如培训中心用户仅能查看本中心数据):
@require_position(UserPositions.Position.TRAINING_CENTER) def center_students(request): # 获取用户关联的培训中心 current_center = request.user_position.center # 过滤仅本中心的学生数据(假设Student模型关联Center) students = Student.objects.filter(center=current_center) # 后续业务逻辑
省级用户仅查看本省数据:
@require_position(UserPositions.Position.PROVINCE) def province_centers(request): current_province = request.user_position.province centers = Center.objects.filter(province=current_province) # ...
4. 模板内权限渲染
根据用户职位动态显示页面内容:
{% if user.userpositions_set.exists %} {% with user_pos=user.userpositions_set.first %} {% if user_pos.position == '4' %} <a href="{% url 'central_dashboard' %}">中央办公室控制台</a> {% elif user_pos.position == '3' %} <a href="{% url 'province_dashboard' user_pos.province.province_id %}">省级控制台</a> {% elif user_pos.position == '2' %} <a href="{% url 'center_dashboard' user_pos.center.id %}">培训中心控制台</a> {% else %} <a href="{% url 'student_dashboard' %}">学生控制台</a> {% endif %} {% endwith %} {% endif %}
三、便捷优化建议
- 给
CulturalUser添加属性,快速获取用户职位:
class CulturalUser(AbstractUser): @property def position(self): try: return self.userpositions_set.get() except UserPositions.DoesNotExist: return None
后续可直接通过request.user.position获取职位信息,无需重复查询。
- 后台管理优化:在Django Admin中,给
UserPositions添加动态字段控制(根据选中的职位显示/隐藏省份/中心字段),可通过自定义Admin表单结合JavaScript实现,提升管理员操作体验。
内容的提问来源于stack exchange,提问作者Ahmad
相关产品推荐
相关产品推荐

