【问题标题】:django forms: default values for bound formsdjango forms: 绑定表单的默认值
【发布时间】:2013-04-08 05:37:31
【问题描述】:

使用这种形式:

class Form(forms.Form):
    name = forms.CharField(required=False, initial='Hello world')

如果我在视图中做这样的事情:

form = Form(request.GET)
if form.is_valid():
    name = form.cleaned_data['name']

即使 request.GET 不包含 name 作为 key,name 的初始值也会丢失。有什么解决方法吗?我希望初始值能够将表单绑定为“默认值”。

【问题讨论】:

    标签: django forms


    【解决方案1】:

    通过稍微修改 Gonzalo 的解决方案,这是正确的方法:

    class Form(forms.Form):
        name = forms.CharField(required=False, initial='Hello world')
    
        def clean_name(self):
            if not self['name'].html_name in self.data:
                return self.fields['name'].initial
            return self.cleaned_data['name']
    

    如果你需要这个,你可以看看 django-filter app。我最近才发现它。

    【讨论】:

      【解决方案2】:

      initial 并不是真的用于设置表单字段的 默认 值。 相反,在向用户显示表单时,它实际上更像是一个占位符实用程序,如果不需要该字段(如您的示例中),它将无法正常工作。

      您可以做的是define a clean_<fieldname> 方法检查该字段是否有空值并返回默认值:

      class Form(forms.Form):
          name = forms.CharField(required=False, initial='Hello world')
      
          def clean_name(self):
              name = self.cleaned_data['name']
              if name is None:
                  return self.fields['name'].initial
              return name
      

      【讨论】:

      • 这是一个有趣的选项,但 if not name: 存在问题。如果在 request.GET 中设置了 name 但设置为空字符串会怎样。在这种情况下,空字符串将被覆盖。
      • 我认为这是你想要的行为,我正在编辑我的答案来处理这种情况:-)
      • name 永远不会是无。即使在 request.GET 中没有设置namecleaned_data['name'] 也将是一个空字符串,因为 name 是一个 CharField。如果name 在request.GET 中作为空字符串发送,它无论如何都是一个空字符串。因此,您无法区分这两种情况。
      【解决方案3】:

      我使用以下模式将默认值设置为表单的初始值-

      class InitialDefaultForm(forms.Form):
          def clean(self):
              cleaned_data = super(InitialDefaultForm, self).clean()
              # if data is not provided for some fields and those fields have an
              # initial value, then set the values to initial value
              for name in self.fields:
                  if not self[name].html_name in self.data and self.fields[name].initial is not None:
                      cleaned_data[name] = self.fields[name].initial
              return cleaned_data
      

      这可确保所有具有初始值且未从用户处获取值的字段都由其初始值填充。

      【讨论】:

        【解决方案4】:

        request.GET 是一个类似字典的对象。

        initial 仅在未绑定表单的情况下有效。

        表单有一个名为data 的属性。此属性在表单初始化期间作为第一个位置参数或 data 关键字参数提供。

        绑定表单是您提供一些数据作为表单的第一个参数的表单,未绑定表单的data 属性设置为无。

        form=Form(request.GET) 表单的初始化中,您提供了第一个位置参数,因此在表单上设置了data 属性,它成为绑定表单。即使request.GET 是空字典也会发生这种情况。而且由于您的表单成为绑定表单,因此name 字段的initial 对其没有影响。

        因此,在您的 GET 请求中,您应该这样做:

        form = Form()
        

        您的 initialname 字段将受到尊重。

        或者,如果您想从 request.GET 中读取 name 并且如果它在那里然后想要使用它而不是字段的初始值,那么在您的视图中具有以下内容。

        name = request.GET.get(name)
        form_level_initial = {}
        if name:
            form_level_initial['name'] = name
        form = Form(initial=form_level_initial)
        

        【讨论】:

        • 对不起,我没有提到如果它没有被 request.GET 覆盖,我需要在验证后在 form.cleaned_data 中显示默认/初始值
        • cleaned_data 和验证应该出现在 POST 请求上,而不是 GET 上。你能解释一下你想要什么吗?
        【解决方案5】:

        这行得通吗:

        initial_form_data = {'name': 'Hello World'}   #put all the initial for fields in this dict
        initial_form_data.update(request.GET)  #any field available in request.GET will override that field in initial_form_data
        form = Form(initial_form_data)
        if form.is_valid():
            name = form.cleaned_data['name']
        

        【讨论】:

        • 这似乎是一个优雅的解决方案,但在我的情况下,它将像 u'' 这样的东西放入表单中,然后触发验证错误。 :( 我在下面想出了一个替代答案来解决这个问题。
        【解决方案6】:

        建议的解决方案要么对我不起作用,要么看起来不太优雅。该文档指定 initial 不适用于绑定表单,这似乎是原始提问者(和我的)用例:

        这就是为什么 initial 值仅针对未绑定的表单显示的原因。对于绑定的表单,HTML 输出将使用绑定的数据。

        https://docs.djangoproject.com/en/1.10/ref/forms/fields/#initial

        我的解决办法是看表单是否应该绑定:

        initial = {'status': [Listing.ACTIVE], 'min_price': 123}     # Create default options
        
        if request.method == 'GET':
            # create a form instance and populate it with data from the request:
            if len(request.GET):
                form = ListingSearchForm(request.GET)       # bind the form
            else:
                form = ListingSearchForm(initial=initial)   # if GET is empty, use default form
        

        您还可以使用其他方式来初始化表单(如上所述)。

        【讨论】:

          【解决方案7】:

          没有一个答案实际上完全符合 clime 的要求。所以这是我对同样问题的解决方案:

          class LeadsFiltersForm(forms.Form):
              TYPE_CHOICES = Lead.TYPES
              SITE_CHOICES = [(site.id, site.name) for site in Site.objects.all()]
          
              type = forms.MultipleChoiceField(
                  choices=TYPE_CHOICES, widget=forms.CheckboxSelectMultiple(),
                  required=False
              )
              site = forms.MultipleChoiceField(
                  widget=forms.CheckboxSelectMultiple(), required=False,
                  choices=SITE_CHOICES
              )
              date_from = forms.DateField(input_formats=['%m-%d-%Y',], required=False,
                                          widget=forms.TextInput(attrs={'placeholder': 'Date From'}),
                                          initial=timezone.now() - datetime.timedelta(days=30))
              date_to = forms.DateField(input_formats=['%m-%d-%Y',], required=False,
                                          widget=forms.TextInput(attrs={'placeholder': 'Date To'}))
          
              defaults = {
                  'type': [val[0] for val in TYPE_CHOICES],
                  'site': [val[0] for val in SITE_CHOICES],
                  'date_from': (timezone.now() - datetime.timedelta(days=30)).strftime('%m-%d-%Y'),
                  'date_to': timezone.now().strftime('%m-%d-%Y')
              }
          
              def __init__(self, data, *args, **kwargs):
                  super(LeadsFiltersForm, self).__init__(data, *args, **kwargs)
                  self.data = self.defaults.copy()
                  for key, val in data.iteritems():
                      if not data.get(key):
                          continue
                      field = self.fields.get(key)
                      if field and getattr(field.widget, 'allow_multiple_selected', False):
                          self.data[key] = data.getlist(key)
                      else:
                          self.data[key] = data.get(key)
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-06-22
            • 2016-05-06
            • 2010-10-10
            • 1970-01-01
            相关资源
            最近更新 更多