You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 04:02:01