【问题标题】:Django: form validation: accepting multiple values for one fieldDjango:表单验证:一个字段接受多个值
【发布时间】:2012-09-23 18:57:05
【问题描述】:

我希望创建一个表单字段,它为给定字段获取多个值、验证它们并将它们存储为列表。

例如,可以运行以下 curl 命令并发布多个称为“电子邮件”的 POST 参数

curl -X POST -d email=test@example.com -d email=test2@example.com http://url/here/

在我看来,我可以执行以下操作以直接从 POST 数据中获取电子邮件列表。

email = request.POST.getlist('email')

但是,我想利用表单验证来清除 POST 数据中指定的所有电子邮件。

理想情况下,我想运行 form.is_valid() 然后访问表单上的 clean_data['email'] 键将返回有效电子邮件地址列表。

我已经研究过使用 MultipleChoice 字段和类似字段(因为它们接受具有相同名称的多个输入),但这些字段要求您事先定义选项。我也考虑过使用表单集,但是对于我在这种情况下尝试做的事情来说,这些似乎过于复杂。

有谁知道以这种方式运行的任何字段?感谢阅读。

【问题讨论】:

  • 您可以通过覆盖表单的__init__ 动态生成MultipleChoicechoices,您将在其中将其传递给电子邮件列表。
  • 感谢兰塔计划的信息。如果我通过 init 覆盖选择,是否还有一种验证输入的好方法(因为所有输入都是有效的,因为它们都是有效的选择)?
  • 我认为这个docs.djangoproject.com/en/1.4/ref/forms/validation/… 对任何与表单/字段验证相关的事情都会很有帮助。

标签: django forms validation field


【解决方案1】:

django-multi-email-field 可以这样做:https://github.com/fle/django-multi-email-field

示例表单代码:

from django import forms
from multi_email_field.forms import MultiEmailField

class SendMessageForm(forms.Form):
    emails = MultiEmailField()

示例查看代码:

assert form.is_valid()
print(form.cleaned_data["emails"])

【讨论】:

    【解决方案2】:

    在 2018 年,这个问题仍然没有令人满意的答案,所以我编写了自己的字段,其行为就像 OP 想要的那样。 Check it out here.

    解决原来的问题:

    forms.py:

    import django.forms as forms
    
    from multivaluefield import MultiValueField
    
    class MultiEmailForm(forms.Form):
        emails = MultiValueField(forms.EmailField(), "email")
    

    查看代码:

    form = MultiEmailForm(request.POST)
    if form.is_valid:
        emails = form.cleaned_data["emails"]
        # do something with emails
    else:
        errors = form.errors
        # do something with errors
    

    【讨论】:

      【解决方案3】:

      我正在寻找类似的东西,我发现了这个:http://djangosnippets.org/snippets/497/

      from django import newforms as forms
      
      class SeparatedValuesField(forms.Field):
          """
          A Django newforms field which takes another newforms field during
          initialization and validates every item in a separated list with
          this field class. Please use it like this::
      
              from django.newforms import EmailField
              emails = SeparatedValuesField(EmailField)
      
          You would be able to enter a string like 'john@doe.com,guido@python.org'
          because every email address would be validated when clean() is executed.
          This of course also applies to any other Field class.
      
          You can define the sepator (default: ',') during initialization with the
          ``separator`` parameter like this::
      
              from django.newforms import EmailField
              emails = SeparatedValuesField(EmailField, separator='###')
      
          If validation succeeds it returns the original data, though the already
          splitted value list can be accessed with the get_list() method.
      
          >>> f = SeparatedValuesField(forms.EmailField)
          >>> f.clean('foo@bar.com,bar@foo.com')
          'foo@bar.com,bar@foo.com'
          >>> f.get_list()
          ['foo@bar.com', 'bar@foo.com']
          >>> f.clean('foobar,foo@bar.com,bar@foo.com')
          Traceback (most recent call last):
              ...
          ValidationError: <unprintable ValidationError object>
          >>> u = SeparatedValuesField(forms.URLField)
          >>> u.clean('http://foo.bar.com,http://foobar.com')
          'http://foo.bar.com,http://foobar.com'
          >>> u.clean('http:foo.bar.com')
          Traceback (most recent call last):
              ...
          ValidationError: <unprintable ValidationError object>
          >>> f = SeparatedValuesField(forms.EmailField, separator='###')
          >>> f.clean('foo@bar.com###bar@foo.com')
          'foo@bar.com###bar@foo.com'
          >>> f.clean('foobar###foo@bar.com###bar@foo.com')
          Traceback (most recent call last):
              ...
          ValidationError: <unprintable ValidationError object>
      
          """
          def __init__(self, base_field=None, separator=',', *args, **kwargs):
              super(SeparatedValuesField, self).__init__(*args, **kwargs)
              self.base_field = base_field
              self.separator = separator
      
          def clean(self, data):
              if not data:
                  raise forms.ValidationError('Enter at least one value.')
              self.value_list = data.split(self.separator)
              if self.base_field is not None:
                  base_field = self.base_field()
                  for value in self.value_list:
                      base_field.clean(value)
              return data
      
          def get_list(self):
              return self.value_list
      
      def _test():
          import doctest
          doctest.testmod()
      
      if __name__ == "__main__":
          _test()
      

      但这并不完全令人满意:例如,对于电子邮件列表,如果只有一封电子邮件无效,则整个字段都无效。

      可能会重写 clean 方法,使其仅返回有效的“base_fields”,而不是完全抛出 ValidationError。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-31
        • 1970-01-01
        • 1970-01-01
        • 2017-10-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多