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)
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.")
现在,这个方法仍然可以返回将要用到的数据的字典,但是不再是强制的。
在这段代码中,如果抛出验证错误,表单将在表单的顶部显示(通常是)描述该问题的一个错误信息。
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 中删除相应的字段。