如何将Python下拉框设为只读?解决ModelChoiceField只读失效问题
解决Django中ModelChoiceField只读无效的问题
嘿,我遇过同样的坑!问题出在HTML的原生行为上:<select>元素根本不支持readonly属性——哪怕你给它加上这个属性,用户照样能点开下拉框选别的选项。这就是为什么你的ReadOnlyFormMixin对普通字段管用,但对ModelChoiceField完全没效果的原因。
下面给你两种可行的解决方案,你可以根据需求选择:
方案一:用disabled属性替代readonly,并处理表单提交
HTML里的<select>认disabled属性,加上之后用户就没法修改选项了,但要注意:disabled的字段不会被包含在POST请求里,所以得额外处理表单验证和数据保存的逻辑。
修改你的ReadOnlyFormMixin:
class ReadOnlyFormMixin(ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field_name, field in self.fields.items(): # 针对下拉框(Select类组件)用disabled,其他字段用readonly if isinstance(field.widget, forms.Select): field.widget.attrs['disabled'] = True else: field.widget.attrs['readonly'] = True # 禁用的字段设为非必填,避免表单验证报错 field.required = False def clean(self): cleaned_data = super().clean() # 如果表单绑定了已有实例,把禁用字段的原始值放回cleaned_data if self.instance.pk: for field_name, field in self.fields.items(): if isinstance(field.widget, forms.Select) or 'readonly' in field.widget.attrs: cleaned_data[field_name] = getattr(self.instance, field_name) return cleaned_data def save(self, *args, **kwargs): # 如果你不需要保存表单(只是展示用),保持pass即可 # 如果需要保存,调用父类的save方法: # return super().save(*args, **kwargs) pass
这个方案会保留下拉框的样式,但用户无法修改,同时确保提交表单时不会丢失原始值。
方案二:把下拉框替换为只读文本框
如果你不需要保留下拉框的视觉样式,直接把ModelChoiceField换成显示选中值的CharField会更简单,也不用处理disabled的提交问题:
修改Manufacturer1Form:
class Manufacturer1Form(ReadOnlyFormMixin, ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 只有当表单绑定了实例时才替换字段 if self.instance.pk: # 替换成显示厂商名称的只读文本框 self.fields['manufacturer'] = forms.CharField( label='Manufacturer', initial=self.instance.manufacturer.name, widget=forms.TextInput(attrs={'readonly': True}) ) class Meta: model = Manufacturer1Relationship exclude = ('part',)
这种方式用户只能看到选中的厂商名称,完全无法修改,适合纯粹的展示场景。
内容的提问来源于stack exchange,提问作者LisaL
相关产品推荐
相关产品推荐

