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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 03:36:03