Django Admin只读外键无权限时仍渲染跳转链接如何修复
问题修复方案
该问题为Django 3.2版本Admin的默认行为:渲染只读外键字段时未做关联模型的权限校验,会直接生成跳转链接。以下是三种可落地的修复方案:
方案一:单个外键字段自定义展示(最简方案,全版本兼容)
直接在你的InspectionAdmin类中修改只读字段的渲染逻辑,假设需要处理的外键字段名为related_obj(替换为你实际的外键字段名):
from django.contrib import admin from .models import Inspection class InspectionAdmin(admin.ModelAdmin): # 将原外键字段从readonly_fields中移除,替换为自定义的展示方法 readonly_fields = ("display_related_obj", ...其余原有只读字段) # 若列表页也需要同步修改,将list_display中的对应字段也替换为该方法名 def display_related_obj(self, obj): # 仅返回关联对象的文本展示,不生成任何链接 if obj.related_obj: return str(obj.related_obj) return "-" # 配置字段显示名称与原字段保持一致 display_related_obj.short_description = "你原字段的展示名称" # 可选配置:保留原字段的排序能力 display_related_obj.admin_order_field = "related_obj"
方案二:全局配置适配所有外键(适合多模型多外键场景)
如果你有大量模型的外键都需要做相同的权限判断,可以自定义通用基础Admin类,所有业务Admin继承该类即可全局生效:
from django.contrib import admin from django.db import models class PermissionBaseAdmin(admin.ModelAdmin): def get_readonly_fields(self, request, obj=None): readonly_fields = list(super().get_readonly_fields(request, obj)) processed_fields = [] for field_name in readonly_fields: # 跳过非数据库字段/方法字段 if not hasattr(self.model._meta, 'get_field'): processed_fields.append(field_name) continue try: db_field = self.model._meta.get_field(field_name) except models.FieldDoesNotExist: processed_fields.append(field_name) continue # 仅处理外键类型的只读字段 if isinstance(db_field, models.ForeignKey): # 校验用户是否有查看关联模型的权限 related_model = db_field.remote_field.model has_view_perm = request.user.has_perm( f"{related_model._meta.app_label}.view_{related_model._meta.model_name}" ) if not has_view_perm: # 无权限则生成自定义展示方法 def custom_display(_, obj): related_val = getattr(obj, field_name) return str(related_val) if related_val else "-" custom_display.short_description = db_field.verbose_name custom_display.admin_order_field = field_name method_name = f"display_{field_name}" setattr(self, method_name, custom_display) processed_fields.append(method_name) continue processed_fields.append(field_name) return processed_fields
后续所有需要该逻辑的Admin类继承PermissionBaseAdmin即可,不需要再单独改每个字段。
方案三:版本升级修复
该问题已在Django 4.0及以上版本修复,新版本Admin会自动判断用户对关联模型的查看权限,无权限时仅展示文本不生成链接。如果你的项目允许升级依赖,可以选择升级到Django 4.2 LTS版本彻底解决该问题。
内容的提问来源于stack exchange,提问作者Ron
相关产品推荐
相关产品推荐

