Django框架(十五)—— forms組件、局部鈎子、全局鈎子


forms組件、局部鈎子、全局鈎子

一、什么是forms組件

forms組件就是一個類,可以檢測前端傳來的數據,是否合法。
例如,前端傳來的郵箱數據,判斷郵件格式對不對,用戶名中不能以什么開頭,等等

二、forms組件的使用

1、使用語法

from django.shortcuts import render, HttpResponse
from django import forms

# 1.先寫一個類,繼承Form
class MyForm(forms.Form):
    # 定義一個屬性,可以用來校驗字符串類型
    # 限制最大長度是8,最小長度是3
    name=forms.CharField(max_length=8,min_length=3)
    pwd=forms.CharField(max_length=8,min_length=3,required=True)
    # 校驗是否是郵箱格式
    email=forms.EmailField()

    

# 2.在視圖函數中使用MyForm來校驗數據
# 實例化產生對象,傳入要校驗的數據(可以傳字典字典,也可以不傳)
myform=MyForm(request.POST)

# 3.校驗,is_valid如果是true表示校驗成功(滿足myform里的條件),反之,校驗失敗
if myform.is_valid():
    # myform.clean_data 表示校驗通過的數據
    print(myform.cleaned_data)
    return HttpResponse('校驗成功')
else:
    print(myform.cleaned_data)
    #校驗失敗的信息,myform.errors  可以當成一個字典,它是所有錯誤信息{name:[列表,]}
    # 每個字段.errors 是一個列表,表示每個字段的錯誤信息
    print(myform.errors)
    return HttpResponse('校驗失敗')

方法總結:

  • myform.clean_data 驗證通過的數據
  • myform.errors 錯誤數據的對象
  • myform.errors.as_data 錯誤數據的信息

2、組件的參數

max_length    # 代表該字段最長為多少
min_length    # 代表該字段最短為多少
error_messages   # 這是設置錯誤信息的屬性
required   # 默認值為True,意思是你傳來的字段必須有它,沒有的話校驗失敗
widget=widgets.TextInput()  # 你在模板渲染的時候,就會渲染成Input框,type為text
lable   # lable='用戶名'

# 例子
 pwd = forms.CharField(max_length=8, min_length=3, required=True, label='密碼',
                          error_messages={'max_length': '最長是8', 'min_length': '最短是3', 'required': '這個必須填'},

3、注意點

  • MyForm實例化時,傳入必須是字典,或者不傳
  • errors 調用這個方法,返回值是對象,你可以通過get取值
  • 要校驗的數據,字段可以多於MyForm類中的字段,但不能少,少相當於該字段沒有數據

三、渲染模板

# form組件可以在視圖函數中使用,也可以在模板中使用
# 視圖層:
def index(request):
    myform = Myform()
    return render(request,'index.html',local())
# 模板層
# 1.渲染方式一:
    <form action='' method='post'>
        用戶名:{{myform:name}} <br>
        <input type='submit' value = '提交'></input>
    </form>
    # 這里的{{myform:name}} 和你寫input框是一樣的效果,就是屬性比input框多一點

# 2.渲染方式二(推薦使用):
    <form action='' method='post'>
        {% for foo in myform%}
            {{ foo.lable }} : {{ foo }}  <br>
        <input type='submit' value = '提交'></input>
    </form>
    # 頁面顯示都是一樣的,foo.lable不是用戶名,是name,但是可以在創建Myform類時,在CharFiel中添加lable='用戶名',這樣就行了。

# 3.渲染方式三:
    <form action='' method='post'>
         {{ myform.as_p }}
        <input type='submit' value = '提交'></input>
    </form>

四、渲染錯誤信息

<form action='' method='post'>
    {% for foo in myform%}
        {{ foo.lable }} : {{ foo }} <span>{{foo.errors.0}}</span><br>
    <input type='submit' value = '提交'></input>
</form>

五、局部鈎子

1、什么是局部鈎子

定義一個函數,名字叫:clean_字段名字,內部,取出該字段,進行校驗,如果通過,將該字段返回,如果失敗,拋異常(ValidationError)

2、定義局部鈎子

# 函數名:clean_字段名字
def clean_name(self):
    # self:當前form對象
    name = self.cleaned_data.get('name')
    if name.startswith('sb'):
    	# 失敗,拋異常,將異常信息以 {'name':value} 寫入errors字典中
    	raise ValidationError('不能以sb開頭')
    # 正常,把name返回到clean_data,將name寫入clean_data字典中
	return name

注意點:

  • 校驗失敗,拋異常,將異常信息以 {'name':value} 寫入 errors 字典中
  • 校驗成功,把name返回到clean_data,寫入clean_data字典中
  • 拋出異常的類型為ValidationError,from django.core.exceptions import ValidationError導入

六、全局鈎子

1、什么是全局鈎子

在寫注冊用戶的時候,有輸入密碼,確認密碼,可以進行布局鈎子處理,處理完畢是不是在進行判斷,判斷他們是否相等,相等的話,就存到數據庫中,不相等就拋個異常。

2、定義全局鈎子

# 重寫clean方法
def clean(self):
    # 程序能走到該函數,前面校驗已經通過了,所以可以從cleaned_data中取出密碼和確認密碼		
    pwd=self.cleaned_data.get('pwd')
    re_pwd=self.cleaned_data.get('re_pwd')
    # 進行自己的校驗
    if pwd==re_pwd: 
        # 通過,直接返回cleaned_data
        return self.cleaned_data
    else:
        # 失敗,拋異常(ValidationError)
        raise ValidationError('兩次密碼不一致')
        

全局鈎子注意點:

  • 校驗失敗,拋異常,將異常信息以 {'__all__':[value,]} 寫入 errors 字典中
  • 校驗成功,返回clean_data字典
  • 拋出異常的類型為ValidationError,from django.core.exceptions import ValidationError導入

鈎子錯誤信息渲染注意點:

  • 局部鈎子拋出的異常會添加到該字段中的錯誤信息中,獲取錯誤信息:

    前台:for循環生成input框,{{ foo.errors.0 }}

  • 全局鈎子拋出的異常會添加到_all_中,獲取錯誤信息:

    后台:myforms.errors.get('__all__')[0] 注意先判斷myforms.errors.get('__all__')是否存在
    前台:{{ myforms.errors.__all__.0 }}

  • 如果程序走到了局部鈎子這一步,說明傳的字典里的數據符合要求,此時就可以從clean_data中取數據,因為此時clean_data中的數據全符合要求,而且clean_data是一個字典

  • 局部鈎子,全局鈎子所拋出異常的類型為ValidationError,以下導入

from django.core.exceptions import ValidationError

七、完整的forms組件校驗

1、視圖層

from django.shortcuts import render, HttpResponse, redirect

# forms組件數據校驗的功能
# 第一步:先要繼承Form
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError


# 寫一個類
class MyForm(forms.Form):
    # 定義一個屬性,可以用來校驗字符串類型
    # 限制最大長度是8,最小長度是3
    name = forms.CharField(max_length=8, min_length=3, label='用戶名'
                           error_messages={'max_length': '最長是8', 'min_length': '最短是3', 'required': '這個必須填'},
                           widget=widgets.TextInput(attrs={'class': 'form-control'}))
    
    pwd = forms.CharField(max_length=8, min_length=3, required=True, label='密碼',
                          error_messages={'max_length': '最長是8', 'min_length': '最短是3', 'required': '這個必須填'},
                          widget=widgets.PasswordInput())
    
    re_pwd = forms.CharField(max_length=8, min_length=3, required=True, label='確認密碼',
                             error_messages={'max_length': '最長是8', 'min_length': '最短是3', 'required': '這個必須填'},
                             widget=widgets.PasswordInput())
    # 校驗是否是郵箱格式
    email = forms.EmailField(label='郵箱', error_messages={'required': '這個必須填', 'invalid': '不符合郵箱格式'})

    # aa = forms.CharField(label='選擇', error_messages={'required': '這個必須填', 'invalid': '不符合郵箱格式'},widget=widgets.CheckboxInput())
    def clean_name(self):
        # self:當前form對象
        name = self.cleaned_data.get('name')
        if name.startswith('sb'):
            # 失敗,拋異常
            raise ValidationError('不能以傻逼開頭')
        # 正常,把name返回
        return name

    def clean(self):
        pwd = self.cleaned_data.get('pwd')
        re_pwd = self.cleaned_data.get('re_pwd')
        if pwd == re_pwd:
            return self.cleaned_data
        else:
            raise ValidationError('兩次密碼不一致')


def index_form(request):
    # 生成對象時(實例化),需要傳入要校驗的數據(字典)
    if request.method == 'GET':
        myform = MyForm()
        return render(request,'indxe2.html',locals())
    elif request.method == 'POST':
        myform = MyForm(request.POST)
        if myform.is_valid():
            # print(myform.cleaned_data)   # 驗證通過的數據
            # models.User.objects.create(name='lqz',pwd='123',re_pwd='123)
            myform.cleaned_data.pop('re_pwd')
            models.User.objects.create(**myform.cleaned_data)
            return redirect('http://www.baidu.com')
        else:
            all_error = myform.errors.get('__all__')
            if all_error:
                all_error = all_error[0]
             # print(myform.errors.as_data)

    return render(request, 'indxe3.html', locals())

2、模板層

<form action="" method="post" novalidate>
    {% for foo in myform %}
        <p>{{ foo.label }}:{{ foo }} <span>{{ foo.errors.0 }}</span></p>
    {% endfor %}

    <input type="submit" value="提交"><span>{{ all_error }}</span>
</form>

注意點:

  • 局部鈎子的錯誤信息:

    前台:for循環生成input框,{{ foo.errors.0 }}

  • 全局鈎子的錯誤信息:

    后台:myforms.errors.get('__all__')[0] 注意先判斷myforms.errors.get('__all__')是否存在
    前台:{{ myforms.errors.__all__.0 }}

  • 校驗全部通過,創建數據時,從clean_data中獲取數據,但是必須要將其中多於的數據pop掉,如clean_data.pop('r_pwd')


免責聲明!

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



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