Django 从源码解析数据验证机制

前言

完整调用链​​
is_valid() errorsfull_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
is_valid
触发full_clean
_clean_fields
字段to_python
执行validators
字段clean方法
clean_钩子
_clean_form
执行表单clean方法
_post_clean
模型实例full_clean
唯一性验证

十、关键设计模式

  1. ​​责任链模式​​:验证责任在字段验证器、字段clean方法、表单clean方法之间传递
  2. ​​模板方法模式​​:通过继承实现验证流程的扩展
  3. ​​异常驱动验证​​:通过抛出ValidationError中断流程
  4. ​​数据净化流水线​​:原始数据 → to_python → validate → clean → 标准化数据

通过深入源码分析,开发者可以:

  • 准确覆盖所有验证阶段
  • 合理扩展自定义验证逻辑
  • 优化验证性能(如减少数据库查询)
  • 精准处理验证错误信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yant224

点滴鼓励,汇成前行星光🌟

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值