diff --git a/app/admin.py b/app/admin.py index 113ffa0c..8cf19fd9 100644 --- a/app/admin.py +++ b/app/admin.py @@ -98,10 +98,19 @@ def _show_by_option(self, obj: NaturalPerson | None, option: str, detail: str): return option, detail return option - def _get_permission_display(self, obj: NaturalPerson | None, perm_key: str): + def _get_permission_display(self, request, obj: NaturalPerson | None, perm_key: str): + # 在新增表单(obj is None)时返回表单字段名; + # 在展示已存在对象时:如果当前用户有编辑权限则返回表单字段名, + # 否则返回只读展示方法名 `perm_`。 if obj is None: return perm_key - return perm_key + try: + if self.has_change_permission(request, obj): + return perm_key + except Exception: + # 如果调用方未传入 request 或出现异常,降级为只读展示 + pass + return f'perm_{perm_key}' def get_normal_fields(self, request, obj: NaturalPerson = None): _m = NaturalPerson @@ -116,7 +125,8 @@ def get_normal_fields(self, request, obj: NaturalPerson = None): f(_m.accept_promote), f(_m.active_score), ]) for perm_config in PERMISSION_CONFIG: - fields.append(self._get_permission_display(obj, perm_config['key'])) + fields.append(self._get_permission_display( + request, obj, perm_config['key'])) return fields def get_student_fields(self, request, obj: NaturalPerson = None): @@ -262,6 +272,28 @@ def _handle_permission(self, request, queryset, perm_key, grant): if not perm_config: return self.message_user(request=request, message='权限配置不存在!', level='error') + # 检查操作者是否有对应的权限检查方法或为超级用户 + checker_name = f'has_{perm_key}_permission' + has_perm_fn = getattr(self, checker_name, None) + if has_perm_fn is None: + # 若未定义专门的权限检查,则仅允许超级用户操作 + if not request.user.is_superuser: + return self.message_user(request=request, + message='操作失败,没有权限,请联系老师!', + level='warning') + else: + try: + if not has_perm_fn(request): + return self.message_user(request=request, + message='操作失败,没有权限,请联系老师!', + level='warning') + except TypeError: + # 兼容 has_*_permission 可能接受 (request, obj) 两种签名 + if not has_perm_fn(request, None): + return self.message_user(request=request, + message='操作失败,没有权限,请联系老师!', + level='warning') + for person in queryset: if grant: person.grant_permission(perm_key) @@ -271,18 +303,30 @@ def _handle_permission(self, request, queryset, perm_key, grant): action = '赋予' if grant else '收回' return self.message_user(request=request, message=f'修改成功!已{action}{perm_config["name"]}!') -# 为每个权限创建grant和revoke方法 +# 为每个权限创建grant和revoke方法,并为动作添加权限检查与描述 for perm_config in PERMISSION_CONFIG: perm_key = perm_config['key'] - + perm_name = perm_config.get('name', perm_key) + + @as_action(f'赋予 {perm_name}', permissions=perm_key) def grant_method(self, request, queryset, key=perm_key): return self._handle_permission(request, queryset, key, True) - + + @as_action(f'收回 {perm_name}', permissions=perm_key) def revoke_method(self, request, queryset, key=perm_key): return self._handle_permission(request, queryset, key, False) - + setattr(NaturalPersonAdmin, f'grant_{perm_key}', grant_method) setattr(NaturalPersonAdmin, f'revoke_{perm_key}', revoke_method) + # 为每个权限创建只读显示方法 + def _perm_display(self, obj, key=perm_key): + try: + return bool(obj.has_permission(key)) + except Exception: + return False + _perm_display.short_description = perm_name + _perm_display.boolean = True + setattr(NaturalPersonAdmin, f'perm_{perm_key}', _perm_display) @admin.register(Freshman) class FreshmanAdmin(admin.ModelAdmin):