[TOC] forms組件 先拋出一個需求: 手動書寫需求 views.py 這裡實現了三個功能: 手寫html頁面獲取用戶輸入信息 將數據傳入後端做數據校驗 如果有錯誤,展示錯誤信息 但是這個頁面手寫麻煩,輸入信息寫錯了,一刷新信息全沒了,很不友好!! 使用forms組件校驗數據 使用forms組 ...
目錄
forms組件
先拋出一個需求:
1.寫一個註冊功能,獲取用戶輸入的用戶名和密碼,提交到後端,後端做校驗
2.用戶名裡面不能含有敏感信息,給出相應的提示
3.如果密碼小於三位,就提示用戶
手動書寫需求
views.py
def register(request):
errors = {'username':'', 'password':''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if 'zf' in username:
errors['username'] = '不能使用該字元'
if len(password) < 4:
errors['password'] = '密碼不能小於三位'
return render(request, 'register.html', locals())
register.html
<form action="" method="post">
<p>
username:<input type="text" name="username">
<span style="color: red">{{ errors.username }}</span>
</p>
<p>
password:<input type="text" name="password">
<span style="color: red">{{ errors.password }}</span>
</p>
<input type="submit">
</form>
這裡實現了三個功能:
- 手寫html頁面獲取用戶輸入信息
- 將數據傳入後端做數據校驗
- 如果有錯誤,展示錯誤信息
但是這個頁面手寫麻煩,輸入信息寫錯了,一刷新信息全沒了,很不友好!!
使用forms組件校驗數據
使用forms組件首先要導入forms模塊, 寫這玩意類似於models
from django import forms
class MyForm(forms.Form):
# username欄位 最多八位, 最少三位
username = forms.CharField(max_length=8, min_length=3)
# password欄位 最多八位, 最少三位
password = forms.CharField(max_length=8, min_length=3)
# email欄位 必須是郵箱格式
email = forms.EmailField()
然後對數據進行校驗, 可以寫一個測試腳本,還可以使用pycharm左下角的Python Console功能,會自動搭建測試腳本
使用測試
校驗數據的方法:
給寫好的類 傳字典數據(待校驗的數據)
form_obj = views.MyForm({'username':'cwz','password':'12','email':'123'})
如何查看校驗的數據是否合法
form_obj.is_valid()
只有全部數據符合校驗規則才為True如何查看不符合規則的欄位及錯誤的理由
form_obj.errors
如何查看符合校驗規則的數據
form_obj.cleaned_data
forms組件中 定義的欄位預設都是必須傳值的 不能少傳
forms組件只會校驗forms類中定義的欄位 如果你多傳了 不會有任何影響
forms組件渲染標簽
1. 方式一
forms組件只會幫你渲染用戶輸入的標簽,不會幫渲染提交按鈕標簽。
views.py
def index(request):
# 渲染標簽,先生成一個空的form類的對象
form_obj = MyForm()
return render(request, 'index.html', locals())
前端頁面:
<p>forms組件渲染的方式1</p>
{{ form_obj.as_p }}
<br>
{{ form_obj.as_ul }}
<br>
{{ form_obj.as_table }}
效果:
總結:這種渲染標簽的方式封裝程度態高 不推薦使用 但是可以用在本地測試
2. 方式二
不推薦使用,比較麻煩
<p>forms組件渲染標簽方式2:</p>
{{ form_obj.username.label }}{{ form_obj.username }}
{{ form_obj.password.label }}{{ form_obj.password }}
{{ form_obj.email.label }}{{ form_obj.email }}
3.方式三
<p>forms組件渲染標簽方式3:</p>
{% for form in form_obj %}
<p>{{ form.label }} {{ form }}</p>
{% endfor %}
若想要label標簽顯示中文,可以指定label標簽:
from django import forms
class MyForm(forms.Form):
# username欄位 最多八位, 最少三位
username = forms.CharField(max_length=8, min_length=3, label='用戶名')
# password欄位 最多八位, 最少三位
password = forms.CharField(max_length=8, min_length=3, label='密碼')
# email欄位 必須是郵箱格式
email = forms.EmailField(label='郵箱')
forms組件展示信息
<form action="" method="post">
{% for form in form_obj %}
<p>{{ form.label }} {{ form }}</p>
{% endfor %}
<input type="submit">
</form>
views.py
from django import forms
class MyForm(forms.Form):
# username欄位 最多八位, 最少三位
username = forms.CharField(max_length=8, min_length=3, label='用戶名')
# password欄位 最多八位, 最少三位
password = forms.CharField(max_length=8, min_length=3, label='密碼')
# email欄位 必須是郵箱格式
email = forms.EmailField(label='郵箱')
def index(request):
# 渲染標簽,先生成一個空的forms類的對象
form_obj = MyForm()
if request.method == 'POST':
form_obj = MyForm(request.POST)
if form_obj.is_valid():
print(form_obj.cleaned_data)
return HttpResponse('數據正確')
else:
print(form_obj.errors)
return render(request, 'index.html', locals())
這玩意是前端做的校驗
註意:
數據的校驗通常前後端都有,但是前端的校驗不堪一擊,可有可無;後端的校驗必須要有而且必須非常全面
在前端form表單加上一個參數(novalidate),就可以不做校驗:<form action="" method="post" novalidate>
前端錯誤信息展示寫法:
<form action="" method="post" novalidate>
{% for form in form_obj %}
<p>{{ form.label }} {{ form }}
<span>{{ form.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit">
</form>
也支持中文顯示信息
from django import forms
class MyForm(forms.Form):
# username欄位 最多八位, 最少三位
username = forms.CharField(max_length=8, min_length=3, label='用戶名', error_messages={
'max_length': '用戶名最長八位',
'min_length': '用戶名最短三位',
'required': '用戶名不能為空',
})
# password欄位 最多八位, 最少三位
password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
'max_length': '密碼最長八位',
'min_length': '密碼最短三位',
'required': '密碼不能為空',
})
# email欄位 必須是郵箱格式
email = forms.EmailField(label='郵箱', error_messages={
'required': '郵箱不能為空',
'invalid': '郵箱格式不正確'
})
form組件自定義校驗
RegexValidator驗證器
from django import forms
from django.core.validators import RegexValidator
class MyForm(forms.Form):
# username欄位 最多八位, 最少三位
username = forms.CharField(max_length=8, min_length=3, label='用戶名', error_messages={
'max_length': '用戶名最長八位',
'min_length': '用戶名最短三位',
'required': '用戶名不能為空',
})
# password欄位 最多八位, 最少三位
password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
'max_length': '密碼最長八位',
'min_length': '密碼最短三位',
'required': '密碼不能為空',
}, validators=[
RegexValidator(r'^[0-9]+$', '請輸入數字'),
RegexValidator(r'^139[0-9]+$', '數字必須要以139開頭') # 可以添加多個正則表達式,從上往下校驗
]
)
鉤子函數 (HOOK)
當你覺得上面的所有校驗還是不能滿足需求,可以考慮鉤子函數
全局鉤子
我們在Fom類中定義 clean() 方法,就能夠實現對欄位進行全局校驗。
class MyForm(forms.Form):
# username欄位 最多八位, 最少三位
username = forms.CharField(max_length=8, min_length=3, label='用戶名', error_messages={
'max_length': '用戶名最長八位',
'min_length': '用戶名最短三位',
'required': '用戶名不能為空',
})
# password欄位 最多八位, 最少三位
password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
'max_length': '密碼最長八位',
'min_length': '密碼最短三位',
'required': '密碼不能為空',
})
re_password = forms.CharField(max_length=8, min_length=3, label='確認密碼', error_messages={
'max_length': '確認密碼最長八位',
'min_length': '確認密碼最短三位',
'required': '確認密碼不能為空',
})
# 校驗密碼 確認密碼是否一致
def clean(self):
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('password')
if not password == re_password:
self.add_error('re_password', '兩次,密碼不一致')
return self.cleaned_data
局部鉤子
我們在Fom類中定義 clean_欄位名() 方法,就能夠實現對特定欄位進行校驗。
class MyForm(forms.Form):
# username欄位 最多八位, 最少三位
username = forms.CharField(max_length=8, min_length=3, label='用戶名', error_messages={
'max_length': '用戶名最長八位',
'min_length': '用戶名最短三位',
'required': '用戶名不能為空',
})
# password欄位 最多八位, 最少三位
password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
'max_length': '密碼最長八位',
'min_length': '密碼最短三位',
'required': '密碼不能為空',
})
re_password = forms.CharField(max_length=8, min_length=3, label='確認密碼', error_messages={
'max_length': '確認密碼最長八位',
'min_length': '確認密碼最短三位',
'required': '確認密碼不能為空',
})
# 校驗用戶名中不能有666
def clean_username(self):
username = self.cleaned_data.get('username')
if '666' in username:
# 給username欄位添加錯誤信息
self.add_error('username', '666是不存在的')
# 將username返回出去
return username
forms組件補充知識點
其他欄位參數
label input對應的提示信息
initial 預設值
required 預設為True 控制欄位是否必填
class MyForm(forms.Form):
# username欄位 最多八位, 最少三位
username = forms.CharField(max_length=8, min_length=3, label='用戶名', initial='預設值',
error_messages={
'max_length': '用戶名最長八位',
'min_length': '用戶名最短三位',
'required': '用戶名不能為空',
}, required=False)
widget 給input框設置樣式及屬性
password = forms.CharField(max_length=8, min_length=3, label='密碼', error_messages={
'max_length': '密碼最長八位',
'min_length': '密碼最短三位',
'required': '密碼不能為空',
}, widget=forms.widgets.PasswordInput() # 這個password欄位是密文的
username = forms.CharField(max_length=8, min_length=3, label='用戶名', initial='預設值',
error_messages={
'max_length': '用戶名最長八位',
'min_length': '用戶名最短三位',
'required': '用戶名不能為空',
}, required=False,
widget=forms.widgets.TextInput({'class': 'form-control c1 c2', 'username': 'cwz'})
)
error_messages
重寫錯誤信息。
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用戶名",
initial="張三",
error_messages={
"required": "不能為空",
"invalid": "格式錯誤",
"min_length": "用戶名最短8位"
}
)
pwd = forms.CharField(min_length=6, label="密碼")
password
class LoginForm(forms.Form):
...
pwd = forms.CharField(
min_length=6,
label="密碼",
widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
)
radioSelect
單radio值為字元串
class LoginForm(forms.Form):
username = forms.CharField(
min_length=8,
label="用戶名",
initial="張三",
error_messages={
"required": "不能為空",
"invalid": "格式錯誤",
"min_length": "用戶名最短8位"
}
)
pwd = forms.CharField(min_length=6, label="密碼")
gender = forms.fields.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性別",
initial=3,
widget=forms.widgets.RadioSelect()
)
單選Select
class LoginForm(forms.Form):
...
hobby = forms.ChoiceField(
choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),
label="愛好",
initial=3,
widget=forms.widgets.Select()
)
多選Select
class LoginForm(forms.Form):
...
hobby = forms.MultipleChoiceField(
choices=((1, "籃球"), (2, "足球"), (3, "雙色球"), ),
label="愛好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
單選checkbox
class LoginForm(forms.Form):
...
keep = forms.ChoiceField(
label="是否記住密碼",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
多選checkbox
class LoginForm(forms.Form):
...
hobby = forms.MultipleChoiceField(
choices=((1, "籃球"), (2, "足球"), (3, "雙色球"),),
label="愛好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
choice欄位註意事項
在使用選擇標簽時,需要註意choices的選項可以配置從資料庫中獲取,但是由於是靜態欄位 獲取的值無法實時更新,需要重寫構造方法從而實現choice實時更新
方式一
from django.forms import Form
from django.forms import widgets
from django.forms import fields
class MyForm(Form):
user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)
def __init__(self, *args, **kwargs):
super(MyForm,self).__init__(*args, **kwargs)
# self.fields['user'].choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].choices = models.Classes.objects.all().values_list('id','caption')
方式二
from django import forms
from django.forms import fields
from django.forms import models as form_model
class FInfo(forms.Form):
authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all()) # 多選
# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all()) # 單選