django 表单验证和字段验证 表单验证和字段验证

full_clean() ),但是通用情况下不需要。

ValidationError,这些方法应该返回验证后的(规整化的)数据的Python 对象。

validate 方法调用之后运行。

表单的验证划分成几个步骤,它们可以定制或覆盖:

  • ValidationError

  • 当你遇到不可以或不想放在validator 中的验证逻辑时,应该覆盖它来处理验证。

  • 你应该不需要覆盖这个方法。

  • cleaned_data 字典中。

  • clean() 方法已经验证过一次数据)。

    CharField),而是一个特定于表单字段特定验证,并规整化数据。

    这个方法返回从cleaned_data 中获取的值,无论它是否修改过。

  • cleaned_data

    errors 属性,它包含验证每个字段时的所有错误。

    add_error()

    ModelForm 文档)。

Form.clean() 方法,无论前面的方法是否抛出过异常。

下面有上面每个方法的示例。

但是,剩余的字段的验证方法仍然会执行。


为了让错误信息更加灵活或容易重写,请考虑下面的准则:

  • code

    # Good
    ValidationError(_('Invalid value'), code='invalid')
    
    # Bad
    ValidationError(_('Invalid value'))
    
  • params 参数:

    # Good
    ValidationError(
        _('Invalid value: %(value)s'),
        params={'value': '42'},
    )
    
    # Bad
    ValidationError(_('Invalid value: %s') % value)
    
  • 这使得重写错误信息时不用考虑变量的顺序或者完全省略它们:

    # Good
    ValidationError(
        _('Invalid value: %(value)s'),
        params={'value': '42'},
    )
    
    # Bad
    ValidationError(
        _('Invalid value: %s'),
        params=('42',),
    )
    
  • gettext 封装错误消息使得它可以翻译:

    # Good
    ValidationError(_('Invalid value'))
    
    # Bad
    ValidationError('Invalid value')
    

所有的准则放在一起就是:

raise ValidationError(
    _('Invalid value: %(value)s'),
    code='invalid',
    params={'value': '42'},
)

如果你想编写可重用的表单、表单字段和模型字段,遵守这些准则是非常必要的。

clean() 方法)且知道永远 不需要重新错误信息,虽然不提倡但你仍然可以选择重写不详细的信息:

ValidationError(_('Invalid value: %s') % value)
New in Django 1.7.

params 字典)。


ValidationError 构造函数。

params,但是传递一个字符串列表也可以工作:

# Good
raise ValidationError([
    ValidationError(_('Error 1'), code='error1'),
    ValidationError(_('Error 2'), code='error2'),
])

# Bad
raise ValidationError([
    _('Error 1'),
    _('Error 2'),
])


因为有时直接看功能在实际中的应用会更容易掌握,下面是一些列小例子,它们用到前面的每个功能。


default_validators 属性中。

SlugField

from django.forms import CharField
from django.core import validators

class SlugField(CharField):
    default_validators = [validators.validate_slug]

这也可以在字段定义时实现,所以:

slug = forms.SlugField()

等同于:

slug = forms.CharField(validators=[validators.validate_slug])

编写Validator 一节可以查到已经存在的Validator 以及如何编写Validator 的一个示例。


完整的类像这样:

from django import forms
from django.core.validators import validate_email

class MultiEmailField(forms.Field):
    def to_python(self, value):
        "Normalize data to a list of strings."

        # Return an empty list if no input was given.
        if not value:
            return []
        return value.split(',')

    def validate(self, value):
        "Check if value consists only of valid emails."

        # Use the parent's handling of required fields, etc.
        super(MultiEmailField, self).validate(value)

        for email in value:
            validate_email(email)

这个验证特定于该类型的字段,与后面如何使用它无关。

ContactForm 来向你演示如何使用这个字段:

class ContactForm(forms.Form):
    subject = forms.CharField(max_length=100)
    message = forms.CharField()
    sender = forms.EmailField()
    recipients = MultiEmailField()
    cc_myself = forms.BooleanField(required=False)

validate() 方法。


recipients 字段上的验证方法,像这样:

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean_recipients(self):
        data = self.cleaned_data['recipients']
        if "fred@example.com" not in data:
            raise forms.ValidationError("You have forgotten about Fred!")

        # Always return the cleaned data, whether you have changed it or
        # not.
        return data


clean() 方法。区别字段和表单之间的差别非常重要。字段是单个数据,表单是字段的集合。

所以你需要记住这个事实,你需要验证的字段可能没有通过初试的字段检查。

例如:

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = super(ContactForm, self).clean()
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject:
            # Only do something if both fields are valid so far.
            if "help" not in subject:
                raise forms.ValidationError("Did not send for 'help' in "
                        "the subject despite CC'ing yourself.")
Changed in Django 1.7:

现在,这个方法仍然可以返回将要用到的数据的字典,但是不再是强制的。

在这段代码中,如果抛出验证错误,表单将在表单的顶部显示(通常是)描述该问题的一个错误信息。

self).clean() 的调用时为了保证维持父类中的验证逻辑。

我们的新代码(代替前面的示例)像这样:

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = super(ContactForm, self).clean()
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject and "help" not in subject:
            msg = "Must put 'help' in subject when cc'ing yourself."
            self.add_error('cc_myself', msg)
            self.add_error('subject', msg)

cleaned_data 中删除相应的字段。