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

如何将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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:45:32