Django之form組件is_valid校驗機制


#先來歸納一下整個流程
#(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)整個校驗過程完成
#下面分析form組件中is_valid校驗的流程
#在分析過程中重點關注_erroes和clean_data這兩個字典
def login(request):
    if request.method == "POST":
        form_obj = LoginForm(request.POST)
        if form_obj.is_valid():
            #如果檢驗全部通過
            print(form_obj.clean_data) #這里全部都沒問題
            return HttpResponse("你好,歡迎回來!")
        else:
            #print(form_obj.clean_data)
            #print(form_obj.errors)
            return render(request, "login.html", {"form_obj": form_obj,)

    form_obj = LoginForm()
    return render(request, "login.html", {"form_obj": form_obj})
#鈎子代碼實例
def clean_user(self):
    val1 = self.cleaned_data.get("user")
    #從正確的字段字典中取值
    #如果這個字符串全部都是由數組組成
    if not val1.isdigit():
        return val1
    else:
        # 注意這個報錯信息已經確定了
        raise ValidationError("用戶名不能全部是數字組成")
        #在校驗的循環中except ValidationError as e:,捕捉的就是這個異常
        #所以能將錯誤信息添加到_errors中
#代碼分析部分
def is_valid(self):
    """
    Returns True if the form has no errors. Otherwise, False. If errors are
    being ignored, returns False.
    如果表單沒有錯誤,則返回true。否則為假。如果錯誤是被忽略,返回false。
    """
    return self.is_bound and not self.errors
    #is_bound默認有值
    #只要self.errors中有一個值,not True = false,返回的就是false

def errors(self):
    """
    Returns an ErrorDict for the data provided for the form
    返回一個ErrorDict在form表單存在的前提下
    """
    if self._errors is None:
        self.full_clean()
    return self._errors

def full_clean(self):
    """
    Cleans all of self.data and populates self._errors and self.cleaned_data.
    清除所有的self.data和本地的self._errors和selif.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()

def _clean_fields(self):
    #每個form組件實例化的過程中都會創建一個fields。fields實質上是一個字典。
    #儲存着類似{"user":"user規則","pwd":"pwd的規則對象"}
    for name, field in self.fields.items():
        #name是你調用的一個個規則字段,field是調用字段的規則
        #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.
        
        value_from_datadict()從數據字典中獲取數據。
        每個部件類型知道如何找回自己的數據,因為有些部件拆分數據在幾個HTML字段。
        """
        #現在假設第一個字段是user
        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)
                #filed是一個對象,field.clean才是真正的規則校驗
            else:
                #你不是文件的時候怎么校驗
                #實際中也是走的這一部,value是你輸入的字段值
                #如果沒有問題,那么原樣返回
                value = field.clean(value)
                #如果一旦出現問題,那么就會走except中的代碼
            self.cleaned_data[name] = value

            if hasattr(self, 'clean_%s' % name):  #這里找是否有clean_XX這個名字存在
                value = getattr(self, 'clean_%s' % name)()  #如果有執行這個函數
                self.cleaned_data[name] = value  #而在鈎子中必須報錯的返回值是確定的
                #如果上面有問題,就又把錯誤添加到了_error中
                #上面這三行代碼是我們能添加鈎子的原因,而且規定了鈎子名的格式

                #如果這個值是正確的話,就會給這個字典添加一個鍵值對
                #剛才在full_clean中self.cleaned_data = {}已經初始化了。
                #{”pws“:123}
        except ValidationError as e:
            self.add_error(name, e)
            #如果出現錯誤,就會給_error這個字典添加一個鍵值對
            #至於add_error這個函數如何添加這個鍵值對的,我們先不管
            #鍵就是name,值就是錯誤信息e
            #在full_clean中已經初始化self._errors = ErrorDict()
            #假設現在user有問題,那么_error就是這樣{”user“:e}

 


免責聲明!

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



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