Django 表单:如何让禁用字段在验证之间保持有效
在某个时候,我需要显示一个被标记为 "disabled"
(通过 disabled="disabled"
属性使其变灰)的下拉选择框(类型为 "select"
)。根据标准(xhtml 和 html4),下拉选择框是不能使用 "readonly"
属性的。需要注意的是,这只是为了展示效果,实际的值还是需要在提交时包含在 POST 请求中。所以我这样做(引用了 django 中表单声明的一部分):
from django import forms
_choices = ['to be', 'not to be']
class SomeForm(forms.Form):
field = forms.ChoiceField(choices=[(item, item) for item in _choices],
widget=forms.HiddenInput()) # the real field
mock_field = forms.ChoiceField(required=False, # doesn't get submitted
choices=[(item, item) for item in _choices],
label="The question",
widget=forms.Select(attrs={'disabled':'disabled'}))
然后它是这样初始化的:
initial_val = 'to be'
form = SomeForm(ititial={'field':initial_val,
'mock_field':initial_val})
一切都很好。直到表单进行验证时,如果其他某个字段验证失败了。这时,表单会重新加载,之前填写的值会被保留,但“mock_field”的值却不会被保留——因为它是禁用的,根本没有被提交。所以它的值就没了。虽然这不影响数据的完整性,但在展示上看起来还是不太好。
有没有什么办法可以保留这个字段的值,尽量少做一些复杂的处理?这个表单是 django.contrib.formtools.FormWizard
的一部分,初始值(还有一些字段)是动态生成的。基本上,已经有很多事情在进行中,如果能不让事情变得更复杂,那就太好了。
2 个回答
浏览器不会提交被禁用的字段。
你可以尝试在表单的 __init__
方法中把 field
的初始值复制到 mock_field
。
def __init__(self, *args, **kwargs):
super(SomeForm, self).__init__(*args, **kwargs)
mock_initial = self.fields['field'].initial
self.fields['mock_field'].initial = mock_initial
这段代码没有经过测试。通常你还会关注 form.data
,但在这种情况下,它和 initial
的值是一样的。
好吧,这是我第一次回答自己的问题,不过我找到了解决办法,虽然这确实有点像是个小窍门,但它有效。
我没有直接从表单实例中获取初始值,因为在构造函数里,self.fields['whatever'].initial
似乎是 None
。相反,我是从关键字参数 "initial" 中获取这个值。然后我把它设置为 "mock" 字段的唯一选择。就像这样:
from django import forms
_choices = ['to be', 'not to be']
class SomeForm(forms.Form):
field = forms.ChoiceField(choices=[(item, item) for item in _choices],
widget=forms.HiddenInput()) # the real field
mock_field = forms.ChoiceField(required=False, # doesn't get submitted
choices=[(item, item) for item in _choices],
label="The question",
widget=forms.Select(attrs={'disabled':'disabled'}))
def __init__(self, *args, **kwargs):
super(SomeForm, self).__init__(*args, **kwargs)
mock_initial = kwargs['initial']['field']
self.fields['mock_field'].choices = [(mock_initial, mock_initial),]
这可能需要一些错误处理。显然,如果没有为实际的 field
提供初始值,这个方法就行不通了。