1、查看is_valid方法,返回self.is_bound和非self.errors

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

2、查看self.is_bound方法,可以看到data或者files只要有一个不为空,即为真

self.is_bound = data is not None or files is not None

3、查看self.errors方法,可以看到判断self._errors如果为None,就执行full_clean()方法,(通过查看self._errors可以看到默认就是None,self._errors = None)

 @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

4、查看self.full_clean方法

执行了self._clean_fields、self._clean_form和self._post_clean三个方法,这3个方法都执行完成后,full_clean方法就执行完成了。

def full_clean(self):
        """
        Cleans all of self.data and populates self._errors and
        self.cleaned_data.
        """
        self._errors = ErrorDict()    #存放错误信息的字典,ErrorDict继承了dict
        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()

5、查看self._clean_fields方法

def _clean_fields(self):
        for name, field in self.fields.items():    #将字典中的所有值都循环出来
            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)
                else:
                    #执行字段中的clean方法(内置校验器的)和自定义校验器的校验,如果有错误就执行下面的add_error方法
                    value = field.clean(value)
                #如果内置校验器和自定义检验器都通过后就将该字段添加到cleaned_data字典中
                self.cleaned_data[name] = value
                如果没有错误,通过反向判断当前form里是否有定义的局部钩子,如果有就加括号执行这个局部钩子的方法,如果错误就执行下面的add_error方法,这里就是源码预留的局部钩子的定义方法,命名为clean_字段名称
                if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                    self.cleaned_data[name] = value  #局部钩子校验通过后将数据保存到cleaned_data字典中,没有通过校验就抛出异常
            except ValidationError as e:
                self.add_error(name, e)

6、查看self._clean_form方法

内置校验器、自定义校验器、局部钩子都执行校验通过后,再执行self._clean_form方法中的self.clean方法

def _clean_form(self):
        try:
            cleaned_data = self.clean()
        except ValidationError as e:
            self.add_error(None, e)
        else:
            if cleaned_data is not None:
                self.cleaned_data = cleaned_data

7、查看self.clean方法

这里就是源码预留的全局钩子的定义方法,如果定义了全局钩子并通过校验,就返回所有数据

def clean(self):
        """
        Hook for doing any extra form-wide cleaning after Field.clean() has been
        called on every field. Any ValidationError raised by this method will
        not be associated with a particular field; it will have a special-case
        association with the field named '__all__'.
        """
        return self.cleaned_data

8、都执行完成后,将错误信息保存在第4步中的self._errors = ErrorDict()这个错误字典中,如果没有错误信息,那么 self._errors = ErrorDict()这个错误字典就是空的。
第3步中的self.full_clean()就执行完成了,并返回return self._errors字典
第1步中的is_valid()就执行完了,如果没有错误信息,return self.is_bound and not self.errors就返回True,否则就返回False


执行顺序:

  1. 内置校验器
  2. 自定义校验器
  3. 局部钩子
  4. 全局钩子
posted on 2019-05-07 06:40  longfei2021  阅读(199)  评论(0编辑  收藏  举报