Forms組件與鉤子函數
目錄
一:Forms組件
1.案例需求:
寫一個註冊功能
1.獲取用戶名和密碼 利用form表單提交數據
2.在後端判斷用戶名和密碼是否符合一定的條件
3.用戶名中不能含有金眉瓶
4.密碼不能少於三位
# 符合條件需要你將提示資訊動態的展示到前端頁面
2.前端
<form action="" method="post">
<p>username:
<input type="text" name="username">
{# 行內標籤 get請求為空 不佔任何標籤 post請求有值 就可以點到對應的數據 #}
<span style="color: red">{{ back_dic.username }}</span>
</p>
<p>password:
<input type="text" name="password">
<span style="color: red">{{ back_dic.password }}</span>
</p>
<input type="submit" class="btn btn-info">
</form>
3.後端
1.無論是post請求還是get請求
頁面都能夠獲取到字典 只不過get請求來的時候 字典值都是空的
2.而post請求來之後 字典可能有值
def ab_form(request):
# 定義一個字典 下面替換的方式
back_dic = {'username':'', 'password':''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if '金眉梅' in username:
back_dic['username'] = '不符合社會主義核心價值觀!'
if len(password) < 3:
back_dic['password'] = '不能太短 不好!'
return render(request, 'ab_form.html', locals())
二:form表單前後端動態交互
1.手動書寫前端獲取用戶數據的html程式碼 渲染html程式碼
2.後端對用戶數據進行校驗 校驗數據
3.對不符合要求的數據進行前端提示 展示提示資訊
1.form組件
# forms組件
能夠完成的事情
1.渲染html程式碼
2.校驗數據
3.展示提示資訊
2.為什麼數據效驗非要去後端 不能在前端利用js直接完成呢?
必記!
1.數據效驗前端可有可無
2.但是後端必須要有!
原因:
1.因為前端的效驗是弱不禁風的 你可以直接修改
2.或者利用爬蟲程式繞過前端頁面直接朝後端提交數據
3.舉例:購物網站
1.選取了貨物之後 會計算一個價格發送給後端 如果後端不做價格的效驗 會造成被別人篡改!
實際情況:
1.實際是獲取到用戶選擇的所有商品主鍵值
2.然後在後端查詢出所有商品的價格 再次計算一遍
3.如果前端一致 那麼完成支付如果不一致直接拒絕
三:基本使用
1.作用於校驗型組件
# views.py
from django import forms
class MyForm(forms.Form):
# username字元串類型最小3位最大8位
username = forms.CharField(min_length=3, max_length=8)
# password字元串類型最小3位最大8位
password = forms.CharField(min_length=3, max_length=8)
# email欄位必須符合郵箱哥哥是 [email protected]
email = forms.EmailField()
2.校驗數據
3.測試環境兩種方式
1.測試環境的準備 可以自己拷貝程式碼準備
2.其實在pycharm左下角已經幫你準備一個測試環境 "python console"
from app01 import views
# 1 將帶校驗的數據組織成字典的形式傳入即可
form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})
# 2 判斷數據是否合法 注意該方法只有在所有的數據全部合法的情況下才會返回True
form_obj.is_valid()
False
# 3 查看所有校驗通過的數據
form_obj.cleaned_data
{'username': 'jason', 'password': '123'}
# 4 查看所有不符合校驗規則以及不符合的原因
form_obj.errors
{
'email': ['Enter a valid email address.']
}
# 5 校驗數據只校驗類中出現的欄位 多傳不影響 多傳的欄位直接忽略
form_obj = views.MyForm({'username':'jason','password':'123','email':'[email protected]','hobby':'study'})
form_obj.is_valid()
True
# 6 校驗數據 默認情況下 類裡面所有的欄位都必須傳值
form_obj = views.MyForm({'username':'jason','password':'123'})
form_obj.is_valid()
False
總結:
也就意味著校驗數據的時候 默認情況下數據可以多傳但是絕不可能少傳
四:渲染標籤
froms組件只會自動幫你渲染獲取用戶輸入的標籤(input select radio checkbox)
不能幫你渲染提交按鈕!
1.後端(生成一個空對象)
def index(request):
# 1 先產生一個空對象
form_obj = MyForm()
# 2 直接將該空對象傳遞給html頁面
return render(request,'index.html',locals())
2.前端利用空對象做操作
3.第一種渲染方式
- 第一種渲染方式:程式碼書寫極少 封裝程度太高 不便於後續的擴展 一般情況下只在本地測試使用
<form action="" method="post">
<p>第一種自動渲染欄位與input框方式</p>
{{ form_obj.as_p }} // p標籤
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
4.第二種渲染方式
- 可擴展性很強 但是需要書寫的程式碼太多 一般情況下不用
<p>第二種渲染方式: 可擴展性很強 但是需要書寫的程式碼太多 一般情況下不用</p>
<p>{{ form_obj.username.label }}:{{ form_obj.username }}</p>
<p>{{ form_obj.password.label }}:{{ form_obj.password }}</p>
<p>{{ form_obj.email.label }}:{{ form_obj.email }}</p>
.label : 拿到前面的框對應的注釋資訊
5.第三種渲染方式
- 第三種渲染方式::程式碼書寫簡單 並且擴展性也高
<p>第三種渲染方式(推薦使用)</p>
{% for form in form_obj %}
<p>{{ form.label }}:{{ form }}</p>
{% endfor %}
6.label屬性作用
label屬性默認展示的是類中定義的欄位首字母大寫的形式
也可以自己修改 直接給欄位對象加label屬性即可
username = forms.CharField(min_length=3,max_length=8,label='用戶名')
五:展示提示資訊
1.渲染錯誤資訊
def index(request):
# 1.先產生一個空對象
form_obj = MyForm()
if request.method == 'POST':
# 獲取用戶數據並且效驗
"""
1.數據獲取繁瑣
2.效驗數據需要構造成字典的格式傳入才行
ps: 但是request.POST可以看成就是一個字典
"""
# 3,效驗數據
form_obj = MyForm(request.POST)
# 4.判斷數據是否合法
if form_obj.is_valid():
# 5.如果合法操作資料庫存儲數據
return HttpResponse('OK')
# 5.如果不合法 有錯誤
# 2.直接將該空對象傳遞給html頁面
return render(request, 'index.html', locals())
# index.html
<form action="" method="post">
<p>第三種渲染方式(推薦使用): 程式碼書寫簡單 並且擴展性也高</p>
{% for form in form_obj %}
<p>
{{ form.label }}:{{ form }}
<span style="color: red">{{ form.errors }}</span>
</p>
{% endfor %}
<input type="submit" class="btn btn-info">
</form>
2.如何讓瀏覽器不做校驗
<form action="" method="post" novalidate>
3.forms組件展示錯誤資訊(必備條件)
1.get請求和post傳給html頁面對象變數名(form_obj)必須一樣
2.forms組件當你的數據不合法的情況下 會保存你上次的數據 讓你基於之前的結果進行修改
更加的人性化
def index(request):
# 1.先產生一個空對象
form_obj = MyForm()
if request.method == 'POST':
# 獲取用戶數據並且效驗
"""
1.數據獲取繁瑣
2.效驗數據需要構造成字典的格式傳入才行
ps: 但是request.POST可以看成就是一個字典
"""
# 3,效驗數據
form_obj = MyForm(request.POST)
# 4.判斷數據是否合法
if form_obj.is_valid():
# 5.如果合法操作資料庫存儲數據
return HttpResponse('OK')
# 5.如果不合法 有錯誤
# 2.直接將該空對象傳遞給html頁面
return render(request, 'index.html', locals())
4.前端
<form action="" method="post" novalidate>
<p>第三種渲染方式(推薦使用): 程式碼書寫簡單 並且擴展性也高</p>
{% for form in form_obj %}
<p>
{{ form.label }}:{{ form }}
<span style="color: red">{{ form.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit" class="btn btn-info">
</form>
5.針對錯誤的提示資訊可以自訂製
- 自訂製提示資訊作用
如果用戶輸入的不符合以下要求,就會根據相應的錯誤進行提示。
class MyForm(forms.Form):
# username字元串類型最小3位最大8位
username = forms.CharField(min_length=3,max_length=8,label='用戶名',
error_messages={
'min_length':'用戶名最少3位',
'max_length':'用戶名最大8位',
'required':"用戶名不能為空"
}
)
# password字元串類型最小3位最大8位
password = forms.CharField(min_length=3,max_length=8,label='密碼',
error_messages={
'min_length': '密碼最少3位',
'max_length': '密碼最大8位',
'required': "密碼不能為空"
}
)
# email欄位必須符合郵箱格式 [email protected]
email = forms.EmailField(label='郵箱',
error_messages={
'invalid':'郵箱格式不正確',
'required': "郵箱不能為空"
}
)
六:forms組件其他參數及補充知識點
label : 欄位名
error_messages : 自定義報錯資訊
initial : 默認值
required : 控制欄位是否必填/可改為False不必填
1.目前問題漏洞
1.欄位沒有form-control
2.針對不同類型的input如何修改
text
password
date
radio
checkbox
3.多個屬性值情況 空格隔開即可
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'}) # 標籤擁有多個樣式類 空格即可
4.第一道關卡裡面還支援正則校驗(手機號等…)
from django.core.validators import RegexValidator
phone = forms.CharField(
validators=[
RegexValidator(r'^[0-9]+$', '請輸入數字'),
RegexValidator(r'^159[0-9]+$', '數字必須以159開頭')
],
)
七:其他類型渲染
1.radio性別單選
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性別",
initial=3,
widget=forms.widgets.RadioSelect()
)
2.select愛好多選
hobby = forms.ChoiceField(
choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
label="愛好",
initial=3,
widget=forms.widgets.Select()
)
3.多選checkbox
hobby2 = forms.MultipleChoiceField(
choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
label="愛好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
八:鉤子函數(HOOK)
1.鉤子函數的作用
在特定的節點自動觸發完成響應操作
2.什麼是鉤子函數?
鉤子函數在forms組件中就類似於第二道關卡,能夠讓我們自定義校驗規則!
3.在forms組件中有兩類鉤子
1.局部鉤子
當你需要給單個欄位增加效驗規則的時候可以使用
2.全局鉤子
當你需要給多個欄位增加效驗規則的時候可以使用
七:實際案例
1.鉤子函數觸發時間:
鉤子函數觸發時間 當第一道關卡走過去後,沒有問題,才執行第二道關卡(鉤子函數)
1.通過第一道關卡的數據會放在self.cleaned_data裡面
2.self就是當前類產生的對象,就是form_obj
2.校驗用戶名中不能含有666 只是校驗username欄位 局部鉤子
# 局部鉤子
def clen_username(self):
# 獲取用戶名
username = self.cleaned_data.get('username')
# 判斷666是否再username內
if '666' in username:
# 提示前端展示錯誤資訊
# add_error內 第一個放 要設置的欄位 第二個放 展示的錯誤資訊
self.add_error('username', '光喊666是不行滴!')
# 將鉤子函數鉤出去數據再放回去
return username
3.校驗密碼和確認密碼是否一致 password confirm兩個欄位 全局鉤子
# 全局鉤子
def clean(self):
# 獲取密碼
password = self.cleaned_data.get('password')
# 獲取用戶確認密碼
confirm_password = self.cleaned_data.get('confirm_password')
# 判斷兩次密碼是否一致
if not confirm_password == password:
# 不一致返回
self.add_error('confirm_password','兩次密碼不一致')
# 將鉤子函數鉤出來的數據再放回去
return self.cleaned_data