Form的is_valid校验规则及验证顺序

一、验证顺序

 

  • 查看form下的源码了解顺序
    BaseForm为基类,中间包含了is_valid校验方法
@html_safe
class BaseForm:
.........
        self.is_bound = data is not None or files is not None .......  @property def errors(self): """Return an ErrorDict for the data provided for the form.""" if self._errors is None: self.full_clean() #---------------调用校验方法 return self._errors def is_valid(self): #--------------开始校验 """Return True if the form has no errors, or False otherwise.""" return self.is_bound and not self.errors # ---------is_bound 中是数据和字段不能为空,否则就不校验,没问题后调用self.errors开始校验 ....... 
  • is_valid 的校验顺序

1. obj = MyForm(request.POST) 创建将要校验的实例

2. obj.is_valid() 开始校验

3. is_valid()校验 is_bound 查看我们创建的MyForm是否空字段,和实例中是否传入了(request.POST)数据

4. is_valid() 调用self.errors 开始校验

5. errors 中调用self.full_clean() 开始校验

    def full_clean(self):   #查看full_clean() 方法
        """
        Clean all of self.data and populate 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() #这是个全局验证钩子,需要自己去子类里重写覆盖

6.查看full_clean()方法中,最后三个函数 self._clean_fields()就开始校验了

    def _clean_fields(self):  #找到_clean_fields() 函数
        for name, field in self.fields.items():
            # value_from_datadict() gets the data from the data dictionaries.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            if field.disabled:
                value = self.get_initial_for_field(field, name)
            else:
                value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
            try:
                if isinstance(field, FileField):
                    initial = self.get_initial_for_field(field, name)
                    value = field.clean(value, initial) #调用field.clean()开始校验
                else:
                    value = field.clean(value)
                self.cleaned_data[name] = value
                if hasattr(self, 'clean_%s' % name): 
                    value = getattr(self, 'clean_%s' % name)()
                  self.cleaned_data[name] = value #预留钩子用来自己做验证格式为 clean_字段名 这样的
            except ValidationError as e:
                self.add_error(name, e)

7.查看field.clean()它就是真的去校验了

    def clean(self, value):
        """
        Validate the given value and return its "cleaned" value as an
        appropriate Python object. Raise ValidationError for any errors.
        """
        value = self.to_python(value)
        self.validate(value)
      self.run_validators(value) #这两段代码  调用默认的正则规则,或者你提供的正则函数去循环验证
        return value

8.验证完成(具体正则函数就不带着看了)

 

1.2 总结顺序

 

1. 首先is_valid()起手,看seld.errors中是否值,只要有值就是flase
2. 接着分析errors.里面判断_errors是都为空,如果为空返回self.full_clean(),否则返回self._errors
3. 现在就要看full_clean(),里面设置_errors和cleaned_data这两个字典,一个存错误字段,一个存储正确字段。
4. 在full_clean最后有一句self._clean_fields(),表示校验字段
5. 在_clean_fields函数中开始循环校验每个字段,真正校验字段的是field.clean(value),怎么校验的不管
6. 在_clean_fields中可以看到,会将字段分别添加到_errors和cleaned_data这两个字典中
7. 结尾部分还设置了钩子,找clean_XX形式的,有就执行。执行错误信息也会添加到_errors中
8. 校验完成

 

二、钩子验证

 

  • 以下为钩子源码:
try:
...
    if hasattr(self, 'clean_%s' % name): 
        value = getattr(self, 'clean_%s' % name)()
        self.cleaned_data[name] = value #预留钩子用来自己做验证格式为 clean_字段名 这样的
except ValidationError as e:
      self.add_error(name, e)

可以看到钩子代码中使用
try ... except ValidationError 错误并添加到errors中

class MyForm(form.Form):
    ...
    # 钩子代码实例 def clean_user(self): value = self.cleaned_data.get("user") # 从正确的字段字典中取值 user_count = models.UserInfo.objects.filter(name=value).count() #查看数据库中这个用户是否存在 if not value.isdigit(): # 如果这个字符串全部都是由数组组成 return value elif user_count: raise ValidationError("用户名已存在") else: # 注意这个报错信息已经确定了 raise ValidationError("用户名不能全部是数字组成") # 在校验的循环中except ValidationError as e:,捕捉的就是这个异常 # 所以能将错误信息添加到_errors中 #全局钩子 _post_clean() def _post_clean(): #自己在这儿全局验证,可以循环验证表单中所有的类容, #父类中默认 pass 占位,不操作 pass

 

转载于:https://www.cnblogs.com/ellisonzhang/p/10709970.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值