目錄
Django Form元件
簡介
Django Form 元件有兩大功能,用於對頁面進行初始化,生成 HTML 標籤,此外還可以對使用者提交對資料進行校驗(顯示錯誤資訊)
- 資料重置
- 校驗規則
form元件和傳統form表單對比
- 當我們用傳統的form表單提交時會重新整理頁面,如果這個我們表單中的某項填錯了,重新整理後我們正確的選項也沒有了
- 傳統的form表單需要我們自己親自校驗每一項,其工作量太大
- form元件前端自動生成表單元素
- form元件可自動驗證表單內容資訊
- form元件可保留使用者上次輸入的資訊
匯入:form django import froms
校驗欄位
ps:這裡資料量較小使用sqlite3
# settings.py需要修改的配置
# LANGUAGE_CODE = 'en-us'
LANGUAGE_CODE = 'zh-Hans' # 修改成中文
# TIME_ZONE = 'UTC'
TIME_ZONE = 'Asia/Shanghai' # 時間使用上海的
USE_I18N = True
USE_L10N = True
USE_TZ = False # 改為當前時區,預設為True
校驗欄位實操
我們在不使用forms的情況下也可以校驗使用者註冊的欄位長度是否符合標準,比如通過len()等方法,但是過於麻煩,下面通過forms來校驗使用者欄位長度;(註冊舉例)
'''
1.註冊頁面,forms校驗,需要定義一個類,來繼承forms.Form
2.自定義類內規定的欄位就是校驗規則
3.例項化類,得到form物件,使用is_valid校驗,校驗成功可以通過物件.cleanded.data獲取到乾淨的資料,校驗失敗通過物件.erros返回錯誤資訊
'''
需要注意的是,例項化物件要傳入校驗資料!
eg:reg_obj = Reg(data=request.POST)
'''Myforms.py'''
from django import forms
class Register(forms.Form):
username = forms.CharField(max_length=8, min_length=3, label='使用者名稱',error_messages={'min_length':'太短了',"required": "該欄位不能為空!"})
password = forms.CharField(max_length=11, min_length=3, label='密碼')
re_password = forms.CharField(max_length=11, min_length=3, label='確認密碼')
email = forms.EmailField(label='郵箱')
- label:輸入框前面的文字資訊。
- error_message:自定義顯示的錯誤資訊,屬性值是字典, 其中 required 為設定不能為空時顯示的錯誤資訊的 key
'''views.py'''
from django.shortcuts import render,HttpResponse,redirect
from app01.My_forms import Register
def register(request):
if request.method == 'GET':
return render(request,'register.html')
else:
# 例項化,傳入校驗資料
reg_form_obj = Register(data=request.POST)
# 判斷校驗是否可以通過
if reg_form_obj.is_valid():
# 校驗通過存入資料庫
print('校驗通過')
print(reg_form_obj.cleaned_data)
reg_form_obj.cleaned_data.pop('re_password')
data = reg_form_obj.cleaned_data
models.Register.objects.create(**data)
# 將校驗通過的資料打散傳入
else:
# 校驗不通過,返回錯誤資訊
print('校驗不通過')
print(reg_form_obj.errors)
return HttpResponse('ok')
'''不理解打散可以看下面這幾個示例'''
# 字串打散
s = 'Hammer'
print(s) # Hammer
print(*s) # H a m m e r
# 元組打散
tup = (1,2,3)
print(tup) # (1, 2, 3)
print(*tup) # 1 2 3
# 列表打散
lst = [1,2,3]
print(lst) # [1, 2, 3]
print(*lst) # 1 2 3
# 字典打散
def func(name,age):
print(name,age)
dic = {'name':'Hammer','age':18}
func(**dic) # Hammer 18
'''urls.py'''
path('register/', views.register)
'''models.py'''
from django.db import models
class Register(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
email = models.EmailField
<!--register.html-->
<form action="" method="post">
<div class="container">
<h1 class="active" style="text-align: center">註冊頁面</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<p>使用者名稱: <input type="text" name="username" class="form-control"></p>
<p>密碼: <input type="password" name="password" class="form-control"></p>
<p>確認密碼: <input type="password" name="re_password" class="form-control"></p>
<p>郵箱: <input type="email" name="email" class="form-control"></p>
<input type="submit" value="提交" class="btn btn-block btn-info">
</div>
</div>
</div>
</form>
# 校驗不通過
校驗不通過
<ul class="errorlist"><li>username<ul class="errorlist"><li>該欄位不能為空!</li></ul></li></ul>
# 校驗通過
校驗通過
{'username': 'HammerZe', 'password': '123', 're_password': '123', 'email': '456@qq.com'}
forms渲染標籤
自己手動寫HTML頁面
<form action="" method="post">
<div class="container">
<h1 class="active" style="text-align: center">註冊頁面</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<p>使用者名稱: <input type="text" name="username" class="form-control"></p>
<p>密碼: <input type="password" name="password" class="form-control"></p>
<p>確認密碼: <input type="password" name="re_password" class="form-control"></p>
<p>郵箱: <input type="email" name="email" class="form-control"></p>
<input type="submit" value="提交" class="btn btn-block btn-info">
</div>
</div>
</div>
</form>
forms渲染標籤(一)
通過在檢視函式中生成一個空form物件,html頁面可以直接使用該物件進行渲染
def register(request):
if request.method == 'GET':
empty_form = Register()
return render(request,'register.html',{'form':empty_form})
else:
# 例項化,傳入校驗資料
reg_form_obj = Register(data=request.POST)
# 判斷校驗是否可以通過
if reg_form_obj.is_valid():
# 校驗通過存入資料庫
print('校驗通過')
print(reg_form_obj.cleaned_data)
else:
# 校驗不通過,返回錯誤資訊
print('校驗不通過')
print(reg_form_obj.errors)
return HttpResponse('ok')
{#forms渲染標籤1#}
<form action="" method="post">
<div class="container">
<h1 class="active" style="text-align: center">註冊頁面2</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<p>使用者名稱: {{ form.username }}</p>
<p>密碼: {{ form.password }}</p>
<p>確認密碼: {{ form.re_password }}</p>
<p>郵箱: {{ form.email }}</p>
<input type="submit" value="提交" class="btn btn-block btn-info">
</div>
</div>
</div>
</form>
總結
如果使用forms渲染,前端會優化處理,如果長度超出會自動擷取等優點
forms渲染標籤(二)【常用】
標籤頁可以通過for迴圈form物件來渲染,標籤前面的欄位可以通過label屬性來拿到,每迴圈一次foo就可以得到一個欄位
{#forms渲染標籤2#}
<form action="" method="post">
<div class="container">
<h1 class="active" style="text-align: center">註冊頁面3</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for foo in form %}
<p>{{ foo.label }}:{{ foo }}</p>
{% endfor %}
<input type="submit" value="提交" class="btn btn-block btn-info">
</div>
</div>
</div>
</form>
forms渲染標籤(三)
渲染標籤也可以通過一句話來渲染,
form.as_p
,as_後面可以跟不同標籤的名字,比如as_table,as_ul····,但是這樣渲染標籤直接寫死,擴充套件性極低!
{#forms渲染標籤3#}
<form action="" method="post">
<div class="container">
<h1 class="active" style="text-align: center">註冊頁面4</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
{{ form.as_p }}
{#{{ form.as_table }}#}
<input type="submit" value="提交" class="btn btn-block btn-info">
</div>
</div>
</div>
</form>
渲染錯誤資訊
- novalidate引數,form標籤中使用,如果新增該引數,不需要校驗或者使用自己的校驗規則
- 渲染錯誤資訊需要傳入
error_messages
引數在類中
error_messages引數中指定的引數型別
error_messages引數指定錯誤資訊型別,以字典的形式指定
- min_length:不滿足最小長度渲染的資訊
- max_length:超過最大長度渲染的資訊
- required:非空,必填,如果沒填渲染的資訊
- invalid:指定郵箱格式
示例
'''views.py'''
def register(request):
if request.method == 'GET':
empty_form = Register()
return render(request,'register.html',{'form':empty_form})
else:
# 例項化,傳入校驗資料
reg_form_obj = Register(data=request.POST)
# 判斷校驗是否可以通過
if reg_form_obj.is_valid():
# 校驗通過存入資料庫
print('校驗通過')
print(reg_form_obj.cleaned_data)
reg_form_obj.cleaned_data.pop('re_password')
data = reg_form_obj.cleaned_data
models.Register.objects.create(**data)
return HttpResponse('成功') # 校驗通過返回一個成功
else:
# 校驗不通過,返回錯誤資訊
print('校驗不通過')
print(reg_form_obj.errors)
return render(request,'register.html',{'form':reg_form_obj})
校驗通過和不通過分別返回不同的資料
<!--前端頁面-->
<form action="" method="post" novalidate>
<h1 class="active" style="text-align: center">註冊頁面
{% for foo in form %}
<p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p>
{% endfor %}
<input type="submit" value="提交">
</form>
需要注意的是,foo.errors返回的是li標籤,是多個,想看單個欄位的錯誤資訊要指定
form渲染樣式之引數配置
上面這樣直接使用渲染的標籤是沒有boostrap元件樣式的,可以通過在類新增引數來定製樣式
匯入:from django.forms import widgets
widget
引數指定input框內的文字格式attrs
引數指定標籤的樣式
'''Myforms.py'''
class Register(forms.Form):
username = forms.CharField(max_length=8, min_length=3, label='使用者名稱',
error_messages={'min_length': '太短了吧,敢不敢大於3cm', "required": "該欄位不能為空!"}
,widget=widgets.TextInput(attrs={'class':'form-control'}))
password = forms.CharField(max_length=11, min_length=3, label='密碼',widget=widgets.PasswordInput(attrs={'class':'form-control'}))
re_password = forms.CharField(max_length=11, min_length=3, label='確認密碼',widget=widgets.PasswordInput(attrs={'class':'form-control'}))
email = forms.EmailField(label='郵箱', error_messages={'invalid': '格式不正確'},widget=widgets.EmailInput(attrs={'class':'form-control'}))
<form action="" method="post" novalidate>
<div class="container">
<h1 class="active" style="text-align: center">註冊頁面3</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for foo in form %}
<p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p>
{% endfor %}
<input type="submit" value="提交" class="btn btn-block btn-info">
</div>
</div>
</div>
</form>
forms元件全域性鉤子和區域性勾子
區域性鉤子使forms校驗更加精準,比如限制欄位長度,是否為數字等···
全域性鉤子可以拿到部分欄位進行比較,比如確認兩次輸入的密碼是否一致,或者兩次的內容是否一致等···
區域性鉤子
from django import forms
from django.core.exceptions import ValidationError
from django.forms import widgets
class Register(forms.Form):
username = forms.CharField(max_length=8, min_length=3, label='使用者名稱',
error_messages={'min_length': '太短了吧,敢不敢大於3cm', "required": "該欄位不能為空!"}
, widget=widgets.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=11, min_length=3, label='密碼',
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
re_password = forms.CharField(max_length=11, min_length=3, label='確認密碼',
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
email = forms.EmailField(label='郵箱', error_messages={'invalid': '格式不正確'},
widget=widgets.EmailInput(attrs={'class': 'form-control'}))
def clean_username(self): # 區域性鉤子
# 校驗名字不能以sb開頭
username = self.cleaned_data.get('username')
if username.startswith('sb'):
# 校驗不通過,丟擲異常
raise ValidationError('不能以sb開頭')
else:
return username # 校驗通過,返回username對應的值,這裡不返回username值,後面檢視函式取不到
總結
- 丟擲異常模組:
from django.core.exceptions import ValidationError
- 區域性鉤子需要注意的是,自定義函式後面需要加對應欄位的名字,比如
clean_username
,以及校驗通過後面要返回校驗的欄位,不然後面拿不到值
全域性鉤子
from django import forms
from django.core.exceptions import ValidationError
from django.forms import widgets
class Register(forms.Form):
username = forms.CharField(max_length=8, min_length=3, label='使用者名稱',
error_messages={'min_length': '太短了吧,敢不敢大於3cm', "required": "該欄位不能為空!"}
, widget=widgets.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=11, min_length=3, label='密碼',
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
re_password = forms.CharField(max_length=11, min_length=3, label='確認密碼',
widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
email = forms.EmailField(label='郵箱', error_messages={'invalid': '格式不正確'},
widget=widgets.EmailInput(attrs={'class': 'form-control'}))
def clean_username(self): # 區域性鉤子
# 校驗名字不能以sb開頭
username = self.cleaned_data.get('username')
if username.startswith('sb'):
# 校驗不通過,丟擲異常
raise ValidationError('不能以sb開頭')
else:
return username # 校驗通過,返回username對應的值,這裡不返回username值,後面檢視函式取不到
def clean(self): # 全域性鉤子
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if password == re_password:
return self.cleaned_data # 返回所有校驗通過的資料
else:
raise ValidationError('兩次密碼不一致')
from django.shortcuts import render,HttpResponse,redirect
from app01.My_forms import Register
from app01 import models
def register(request):
if request.method == 'GET':
empty_form = Register()
return render(request,'register.html',{'form':empty_form})
else:
# 例項化,傳入校驗資料
reg_form_obj = Register(data=request.POST)
# 判斷校驗是否可以通過
if reg_form_obj.is_valid():
# 校驗通過存入資料庫
print('校驗通過')
print(reg_form_obj.cleaned_data)
reg_form_obj.cleaned_data.pop('re_password')
data = reg_form_obj.cleaned_data
models.Register.objects.create(**data)
return HttpResponse('成功') # 校驗通過返回一個成功
else:
# 校驗不通過,返回錯誤資訊
print('校驗不通過')
print(reg_form_obj.errors)
global_error = reg_form_obj.errors.get('__all__')[0] # 全域性鉤子錯誤
# local_error = reg_form_obj.errors.get('username')[0] # 區域性鉤子錯誤
return render(request,'register.html',{'form':reg_form_obj,'global_error':global_error})
<form action="" method="post" novalidate>
<div class="container">
<h1 class="active" style="text-align: center">註冊頁面3</h1>
<div class="row">
<div class="col-md-8 col-md-offset-2">
{% for foo in form %}
<p>{{ foo.label }}:{{ foo }}<span style="color: tomato">{{ foo.errors.0 }}</span></p>
{% endfor %}
<input type="submit" value="提交" class="btn btn-block btn-info"> <span style="color: #aa100e">{{ global_error }}</span>
</div>
</div>
</div>
</form>
總結
- 全域性鉤子獲取錯誤可以通過
__all__
獲取 - 渲染標籤或者頁面要例項化form空物件
錯誤資訊顯示
報錯資訊顯示順序:
- 先顯示欄位屬性中的錯誤資訊,然後再顯示區域性鉤子的錯誤資訊。
- 若顯示了欄位屬性的錯誤資訊,就不會顯示區域性鉤子的錯誤資訊。
- 若有全域性鉤子,則全域性鉤子是等所有的資料都校驗完,才開始進行校驗,並且全域性鉤子的錯誤資訊一定會顯示