前言
完整调用链:
is_valid()
→ errors
→ full_clean()
→ _clean_fields()
→ _clean_form()
→ _post_clean()
一、验证入口:is_valid()
方法
文件路径:django/forms/forms.py
class BaseForm:
def is_valid(self):
"""返回表单数据是否全部验证通过"""
return self.is_bound and not self.errors
@property
def errors(self):
"""触发完整验证流程"""
if self._errors is None:
self.full_clean()
return self._errors
二、核心验证流程:full_clean()
class BaseForm:
def full_clean(self):
"""
执行完整验证的三阶段:
1. 字段级验证 (_clean_fields)
2. 表单级验证 (_clean_form)
3. 模型级后处理 (_post_clean)
"""
self._errors = ErrorDict()
if not self.is_bound: # 未绑定数据直接返回
return
self.cleaned_data = {}
# 阶段1:逐个字段验证
self._clean_fields()
# 阶段2:表单级交叉验证
self._clean_form()
# 阶段3:模型表单扩展点
self._post_clean()
三、字段级验证详解 (_clean_fields
)
class BaseForm:
def _clean_fields(self):
for name, field in self.fields.items():
# 获取原始值
raw_value = self.data.get(name, field.initial)
try:
# 第一步:字段的to_python转换
value = field.to_python(raw_value)
# 第二步:执行字段验证器
self.clean_validate_field(field, value)
# 第三步:执行字段的clean方法
value = field.clean(value)
# 第四步:执行clean_<fieldname>钩子
value = self.clean_field_hook(name, value)
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
def clean_validate_field(self, field, value):
"""执行字段的validators验证器"""
if value in field.empty_values:
return
for validator in field.validators:
validator(value)
四、表单级验证 (_clean_form
)
class BaseForm:
def _clean_form(self):
try:
# 执行表单的clean()方法
cleaned_data = self.clean() # 开发者自定义的交叉验证逻辑
if cleaned_data is not None:
self.cleaned_data = cleaned_data
except ValidationError as e:
self.add_error(None, e) # 非字段错误
五、模型验证扩展 (_post_clean
)
文件路径:django/forms/models.py
class ModelForm(BaseModelForm):
def _post_clean(self):
"""模型表单特有验证阶段"""
opts = self._meta
# 模型实例的clean方法
try:
self.instance.full_clean(exclude=opts.exclude)
except ValidationError as e:
self._update_errors(e)
# 唯一性约束检查(需数据库访问)
self.validate_unique()
六、验证器执行流程
文件路径:django/forms/fields.py
class Field:
def run_validators(self, value):
"""执行字段级别的验证器链"""
errors = []
for v in self.validators:
try:
v(value)
except ValidationError as e:
if hasattr(e, 'code') and e.code in self.error_messages:
e.message = self.error_messages[e.code]
errors.extend(e.error_list)
if errors:
raise ValidationError(errors)
七、自定义验证钩子
1. 字段级钩子
class LoginForm(forms.Form):
username = forms.CharField()
def clean_username(self):
"""自动触发的字段后处理"""
value = self.cleaned_data['username']
if not User.objects.filter(username=value).exists():
raise ValidationError("用户不存在")
return value.lower() # 标准化数据
2. 表单级钩子
class RegisterForm(forms.ModelForm):
def clean(self):
"""跨字段验证示例"""
data = super().clean()
if data['password'] != data['confirm_password']:
self.add_error('confirm_password', "密码不一致")
return data
八、错误处理机制
class BaseForm:
def add_error(self, field, error):
"""错误收集核心方法"""
if not isinstance(error, ValidationError):
error = ValidationError(error)
if field is None: # 非字段错误
self._errors.setdefault(NON_FIELD_ERRORS, []).extend(error.error_list)
else:
self._errors.setdefault(field, []).extend(error.error_list)
if field in self.cleaned_data: # 移除无效数据
del self.cleaned_data[field]
九、验证流程图示
- fdasf
十、关键设计模式
- 责任链模式:验证责任在字段验证器、字段clean方法、表单clean方法之间传递
- 模板方法模式:通过继承实现验证流程的扩展
- 异常驱动验证:通过抛出
ValidationError
中断流程 - 数据净化流水线:原始数据 → to_python → validate → clean → 标准化数据
通过深入源码分析,开发者可以:
- 准确覆盖所有验证阶段
- 合理扩展自定义验证逻辑
- 优化验证性能(如减少数据库查询)
- 精准处理验证错误信息