Django:表单验证:接受一个字段的多个值

时间:2012-10-02 21:18:30

标签: django forms validation field

我正在寻找创建一个表单字段,该表单字段为给定字段获取多个值,验证它们并将它们存储为列表。

例如,可以运行以下curl命令并发布名为'email'的几个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(),然后访问表单上的cleaning_data ['email']键将返回有效电子邮件地址列表。

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

有没有人知道以这种方式行事的任何领域?谢谢你的阅读。

2 个答案:

答案 0 :(得分:2)

我正在寻找类似的东西,我发现了这个: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。

答案 1 :(得分:0)

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