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