Django13-ModelForm中的is_valid及局部鉤子、全局鉤子源碼解析

一、查看is_valid方法,返回self.is_bound和非self.errorside

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.is_bound方法,能夠看到data或者files只要有一個不爲空,即爲真post

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

三、查看self.errors方法,能夠看到判斷self._errors若是爲None,就執行full_clean()方法,(經過查看self._errors能夠看到默認就是None,self._errors = None)ui

 @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

四、查看self.full_clean方法this

執行了self._clean_fields、self._clean_form和self._post_clean三個方法,這3個方法都執行完成後,full_clean方法就執行完成了。spa

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()

五、查看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)

六、查看self._clean_form方法code

內置校驗器、自定義校驗器、局部鉤子都執行校驗經過後,再執行self._clean_form方法中的self.clean方法orm

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

七、查看self.clean方法blog

這裏就是源碼預留的全局鉤子的定義方法,若是定義了全局鉤子並經過校驗,就返回全部數據繼承

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

八、都執行完成後,將錯誤信息保存在第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. 全局鉤子
相關文章
相關標籤/搜索