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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM