在前面的例子里面 http://beanxyz.blog.51cto.com/5570417/1963702,已经演示了form可以自动地对正则进行合法的判断,如果不合法,会直接显示错误信息。
但是这个功能并不完善,比如说一个数据可能正则判断合法了,但是不符合唯一性的判断,那么怎么处理?我们可以通过 form的 hook(钩子)进行自定义。
如果我们查看 Is_valid这个方法,我们可以看见
def is_valid(self):
"""
Returns True if the form has no errors. Otherwise, False. If errors are
being ignored, returns False.
"""
return self.is_bound and not self.errors
追踪self.errors
@property
def errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
追踪 full_clean(), 这里是系统给我们预留的3个hook,分别代表对字段的clean,对整个form的clean,和clean之后的操作
def full_clean(self):
"""
Cleans all of self.data and populates self._errors and
self.cleaned_data.
"""
self._errors = ErrorDict()
if not self.is_bound: # Stop further processing.
return
self.cleaned_data = {}
# If the form is permitted to be empty, and none of the form data has
# changed from the initial data, short circuit any validation.
if self.empty_permitted and not self.has_changed():
return
self._clean_fields()
self._clean_form()
self._post_clean()
因此form验证的顺序是,默认的正则判断-》对应每一个字段单独的验证(clean)-》整个form的clean验证-》clean之后的操作
实例:
from django.core.exceptions import ValidationError
from django import forms
from django.forms import widgets
from django.forms import fields
from app01 import models
class RegisterForm(forms.Form):
user = fields.CharField
email = fields.EmailField
def clean_user(self): # 对user做一个单独的验证
c = models.UserType.objects.filter(name=self.cleaned_data['user'])
if c : # 如果用户名已经存在,提示报错信息
raise ValidationError('用户名已经存在',code='xxx')
else: # 不存在,验证通过
return self.cleaned_data['user']
def clean_email(self): # 对email做单独的验证
# 验证必须要有返回值
return self.cleaned_data['email']
# 验证顺序:
# 先user字段,在clean_user方法
# 再email字段,在clean_email方法
def register(request):
from cmdb.forms import RegisterForm from django.core.exceptions import NON_FIELD_ERRORS
obj = RegisterForm(request.POST) if obj.is_valid():
obj.cleand_data else:
obj.errors
{
'user':[{'code':'required','message':'xxxx'}],
'pwd':[{'code':'required','message':'xxxx'}],
# 上面每个字段的错误信息放在里面,那clean总的错误信息放在哪里?
'__all__':[], # 特殊的整体错误信息,放在这里
# NON_FIELD_ERRORS:[], 和 __all__ 一个意思。
}