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

在Django Admin中按用户组限制Exam模型状态字段可选值

解决方案

要实现这个权限控制需求,我们可以通过重写Django Admin的get_form和save_model方法,结合用户组来动态限制状态选项并校验变更合法性,具体步骤如下:

1. 准备用户组与基础权限

首先在Django Admin后台创建两个用户组:X组和Y组,并为这两个组分配Exam模型的修改权限(即change_exam权限)。

2. 修改ExamAdmin代码

from django.core.exceptions import PermissionDenied
from django.contrib import admin
from your_app.models import Exam

# 确保状态常量与模型中定义一致
PASS = 'PASS'
FAILED = 'FAILED'
GREAT = 'GREAT'

@admin.register(Exam)
class ExamAdmin(NestedModelAdmin):
    list_display = ('state',)

    def get_form(self, request, obj=None, **kwargs):
        form = super().get_form(request, obj, **kwargs)
        user_groups = request.user.groups.values_list('name', flat=True)

        # 仅处理编辑场景(新增场景需求未提及,默认保留默认状态逻辑)
        if obj:
            allowed_states = []
            if 'X组' in user_groups:
                # X组仅能在当前状态为FAILED时修改为PASS,其他场景设为只读
                if obj.state == FAILED:
                    allowed_states = [PASS]
                else:
                    form.base_fields['state'].widget.attrs['readonly'] = True
            elif 'Y组' in user_groups:
                # Y组可在FAILED时改PASS,PASS时改GREAT,其他场景设为只读
                if obj.state == FAILED:
                    allowed_states = [PASS]
                elif obj.state == PASS:
                    allowed_states = [GREAT]
                else:
                    form.base_fields['state'].widget.attrs['readonly'] = True

            # 过滤可选状态选项
            if allowed_states:
                form.base_fields['state'].choices = [
                    (state, state) for state in allowed_states
                ]
        return form

    def save_model(self, request, obj, form, change):
        # 仅处理修改操作
        if change:
            original_state = self.model.objects.get(pk=obj.pk).state
            new_state = obj.state
            user_groups = request.user.groups.values_list('name', flat=True)

            # 校验X组用户的状态变更合法性
            if 'X组' in user_groups:
                if not (original_state == FAILED and new_state == PASS):
                    raise PermissionDenied("你仅能将FAILED状态修改为PASS")
            # 校验Y组用户的状态变更合法性
            elif 'Y组' in user_groups:
                valid_transitions = [(FAILED, PASS), (PASS, GREAT)]
                if (original_state, new_state) not in valid_transitions:
                    raise PermissionDenied("你仅能将FAILED改为PASS,或PASS改为GREAT")

        super().save_model(request, obj, form, change)

方案说明

  • get_form方法:在生成编辑表单时,根据用户所在组和当前实例的状态,动态限制可选择的状态选项,非允许场景直接将状态字段设为只读,从前端层面限制操作。
  • save_model方法:在保存实例前做最终校验,防止用户通过绕过前端表单的方式(如API调用、数据库直接修改)非法变更状态,从后端层面保障权限控制的安全性。

内容的提问来源于stack exchange,提问作者Mehdi Aria

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 09:36:27