代码之家  ›  专栏  ›  技术社区  ›  shylent

Django窗体:使禁用的字段在验证之间保持不变

  •  7
  • shylent  · 技术社区  · 15 年前

    在某个时刻,我需要显示 "disabled" (被灰熏出来) disabled="disabled" 属性)类型的输入 "select" . 根据标准(XHTML和HTML4)的规定,输入类型为 “选择” 不能有 "readonly" 属性。请注意,这仅用于演示目的,实际值必须最终显示在日志中。下面是我要做的(引用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})
    

    一切都很好。好吧,直到表单得到验证,而其他字段中的一个没有通过验证。当发生这种情况时,将重新加载表单并保留值,但不是“模拟域”中的一个-它从未被提交(它被禁用)。所以它没有被保存。虽然这不会影响数据的完整性,但它仍然不太适合表示。

    有没有什么方法可以尽可能少地利用黑客来保护这个领域?该窗体是 django.contrib.formtools.FormWizard 初始值(和一些字段)是动态生成的。基本上,已经发生了很多事情,如果不可能把事情复杂化,那就太好了。

    2 回复  |  直到 15 年前
        1
  •  3
  •   muhuk    15 年前

    浏览器不发布禁用的字段。

    你可以试着复制 field s初始值到 mock_field 在你的表格里 __init__

    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

        2
  •  1
  •   shylent    15 年前

    嗯,这将是我第一次回答我的问题,但我已经找到了一个解决方案,而且(虽然它确实是一个黑客)它是有效的。

    不是从表单实例获取初始值, self.fields['whatever'].initial 似乎是 None 在构造函数内部,我从关键字参数“initial”获取值。然后我把它设置为“模拟”字段的唯一选择。这样地:

    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 .