如何为Django ModelAdmin只读表单字段添加id属性以便JavaScript定位
方案1:动态修改表单widget属性(更推荐)
不通过readonly_fields配置只读状态,改为在表单初始化时动态给字段widget添加禁用/只读属性,Django会完整保留原生表单的id属性,和可编辑状态的id完全一致(格式为id_<字段名>),不需要修改JS定位逻辑。
针对select字段的实现代码如下:
from django import forms from django.contrib import admin from .models import YourModel # 替换为你自己的模型 class YourModelForm(forms.ModelForm): class Meta: model = YourModel fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 存在实例主键时为更新场景,将字段设为只读 if self.instance and self.instance.pk: # select原生不支持readonly属性,通过JS事件阻止选项变更 self.fields["your_select_field"].widget.attrs.update({ "readonly": "readonly", "onfocus": "this.defaultIndex = this.selectedIndex", "onchange": "this.selectedIndex = this.defaultIndex" }) # 如果不需要提交该字段的值,可直接设为disabled,不需要加上面的事件 # self.fields["your_select_field"].widget.disabled = True class YourModelAdmin(admin.ModelAdmin): form = YourModelForm
方案2:自定义只读字段渲染函数
如果需要完全自定义只读状态的展示样式,可通过自定义字段渲染方法手动添加id属性:
from django.contrib import admin from django.utils.html import format_html from .models import YourModel class YourModelAdmin(admin.ModelAdmin): def get_readonly_fields(self, request, obj=None): # 更新场景将原字段加入只读列表 if obj: return ["your_select_field"] + list(self.readonly_fields) return self.readonly_fields # 自定义字段渲染逻辑 def render_your_select_field(self, obj): # 手动生成和可编辑状态id一致的元素 return format_html( '<span id="id_your_select_field">{}</span>', # 替换为你要展示的选项文本 obj.get_your_select_field_display() ) render_your_select_field.short_description = "你的select字段展示名" def get_fields(self, request, obj=None): fields = super().get_fields(request, obj) if obj: # 更新场景替换原字段为自定义渲染的字段 fields = [f for f in fields if f != "your_select_field"] + ["render_your_select_field"] return fields
适用场景说明
- 优先选方案1,代码改动量小,保留原生表单结构,不会出现表单提交取值异常的问题
- 需要自定义只读状态的UI样式时再选方案2,注意手动保证自定义元素的
id和原生可编辑状态的id一致即可
内容的提问来源于stack exchange,提问作者Ian
相关产品推荐
相关产品推荐

