新手上路
Django的Form主要具備一下幾大功能:javascript
- 生成HTML標籤
- 驗證用戶數據(顯示錯誤信息)
- HTML Form提交保留上次提交數據
- 初始化頁面顯示內容
經過Form驗證有倆種形式html
- Form表單提交
驗證、並能夠保留上次內容java
- Ajax提交
驗證、無需上次內容(Ajax提交數據頁面不會刷新)python
返回HttpResponsegit
前面根據回調函數值相應地作出跳轉或者顯示錯誤信息正則表達式
小試牛刀
一、建立Form類數據庫
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
# 建立一個類
from
django
import
forms
from
django.forms
import
fields
class
DiyForm(forms.Form):
# 類中建立字段 例如 IntegerField包含了正則表達式
user
=
fields.CharField(
max_length
=
18
,
min_length
=
6
,
required
=
True
,
error_messages
=
{
'max_length'
:
'用戶名過長'
,
'min_length'
:
'用戶名太短'
,
'required'
:
'用戶名不能爲空'
,
'invalid'
:
'輸入類型錯誤'
}
)
pwd
=
fields.CharField(
required
=
True
,
min_length
=
8
,
error_messages
=
{
'required'
:
'密碼不可爲空'
,
'min_length'
:
'密碼至少爲8位'
}
)
age
=
fields.IntegerField(
required
=
True
,
error_messages
=
{
'required'
:
'年齡不可爲空'
,
'invalid'
:
'年齡必須爲數字'
}
)
email
=
fields.EmailField(
required
=
True
,
min_length
=
8
,
error_messages
=
{
'required'
:
'郵箱不可爲空'
,
'min_length'
:
'郵箱長度不匹配'
,
'invalid'
:
'郵箱規則不符合'
}
)
|
二、View函數django
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
from
django.shortcuts
import
render,HttpResponse,redirect
def
f1(request):
if
request.method
=
=
'GET'
:
obj
=
DiyForm()
# 實例化 傳參可進行模板渲染 生成Html代碼
return
render(request,
'f1.html'
, {
'obj'
:obj})
else
:
obj
=
DiyForm(request.POST)
# 判斷是否所有驗證成功 逐一交給類字段裏面一一進行驗證、像一層濾網
if
obj.is_valid():
# 用戶提交的數據 驗證成功的信息
print
(
'驗證成功'
, obj.cleaned_data)
return
redirect(
'http://www.baidu.com'
)
else
:
print
(
'驗證失敗'
, obj.errors)
# 封裝的錯誤信息
return
render(request,
'f1.html'
, {
'obj'
: obj})
|
三、Html生成函數
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<!DOCTYPE html>
<html lang
=
"en"
>
<head>
<meta charset
=
"UTF-8"
>
<title>DjangoForm<
/
title>
<
/
head>
<body>
<form action
=
"/f1.html"
method
=
"post"
novalidate enctype
=
"multipart/form-data"
>
<p>{{ obj.user }}{{ obj.errors.user.
0
}}<
/
p>
<p>{{ obj.pwd }}{{ obj.errors.pwd.
0
}}<
/
p>
<p>{{ obj.age }}{{ obj.errors.age.
0
}}<
/
p>
<p>{{ obj.email }}{{ obj.errors.email.
0
}}<
/
p>
<
input
type
=
"submit"
value
=
"提交"
>
<
/
form>
<
/
body>
<
/
html>
|
初露鋒芒
建立Form類時,主要涉及到 【字段】 和 【插件】,字段用於對用戶請求數據的驗證,插件用於自動生成HTML;post
一、Django中Form類內置字段以下:
經常使用字段
1
2
3
4
5
6
7
8
9
10
11
12
13
|
用於保存正則表達式
ChoiceField
*
*
*
*
*
MultipleChoiceField
CharField
IntegerField
DecimalField
DateField
DateTimeField
EmailField
GenericIPAddressField
FileField
RegexField
|
詳細字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
Field
required
=
True
, 是否容許爲空
widget
=
None
, HTML插件
label
=
None
, 用於生成Label標籤或顯示內容
initial
=
None
, 初始值
help_text
=
'', 幫助信息(在標籤旁邊顯示)
error_messages
=
None
, 錯誤信息 {
'required'
:
'不能爲空'
,
'invalid'
:
'格式錯誤'
}
show_hidden_initial
=
False
, 是否在當前插件後面再加一個隱藏的且具備默認值的插件(可用於檢驗兩次輸入是否一直)
validators
=
[], 自定義驗證規則
localize
=
False
, 是否支持本地化
disabled
=
False
, 是否能夠編輯
label_suffix
=
None
Label內容後綴
CharField(Field)
max_length
=
None
, 最大長度
min_length
=
None
, 最小長度
strip
=
True
是否移除用戶輸入空白
IntegerField(Field)
max_value
=
None
, 最大值
min_value
=
None
, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value
=
None
, 最大值
min_value
=
None
, 最小值
max_digits
=
None
, 總長度
decimal_places
=
None
, 小數位長度
BaseTemporalField(Field)
input_formats
=
None
時間格式化
DateField(BaseTemporalField) 格式:
2015
-
09
-
01
TimeField(BaseTemporalField) 格式:
11
:
12
DateTimeField(BaseTemporalField)格式:
2015
-
09
-
01
11
:
12
DurationField(Field) 時間間隔:
%
d
%
H:
%
M:
%
S.
%
f
...
RegexField(CharField)
regex, 自定製正則表達式
max_length
=
None
, 最大長度
min_length
=
None
, 最小長度
error_message
=
None
, 忽略,錯誤信息使用 error_messages
=
{
'invalid'
:
'...'
}
EmailField(CharField)
...
FileField(Field)
allow_empty_file
=
False
是否容許空文件
ImageField(FileField)
...
注:須要PIL模塊,pip3 install Pillow
以上兩個字典使用時,須要注意兩點:
-
form表單中 enctype
=
"multipart/form-data"
-
view函數中 obj
=
MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices
=
(), 選項,如:choices
=
((
0
,
'上海'
),(
1
,
'北京'
),)
required
=
True
, 是否必填
widget
=
None
, 插件,默認select插件
label
=
None
, Label內容
initial
=
None
, 初始值
help_text
=
'', 幫助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset,
# 查詢數據庫中的數據
empty_label
=
"---------"
,
# 默認空顯示內容
to_field_name
=
None
,
# HTML中value的值對應的字段
limit_choices_to
=
None
# ModelForm中對queryset二次篩選
ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce
=
lambda
val: val 對選中的值進行一次轉換
empty_value
=
'' 空值的默認值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce
=
lambda
val: val 對選中的每個值進行一次轉換
empty_value
=
'' 空值的默認值
ComboField(Field)
fields
=
() 使用多個驗證,以下:即驗證最大長度
20
,又驗證郵箱格式
fields.ComboField(fields
=
[fields.CharField(max_length
=
20
), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象類,子類中能夠實現聚合多個字典去匹配一個值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats
=
None
, 格式列表:[
'%Y--%m--%d'
,
'%m%d/%Y'
,
'%m/%d/%y'
]
input_time_formats
=
None
格式列表:[
'%H:%M:%S'
,
'%H:%M:%S.%f'
,
'%H:%M'
]
FilePathField(ChoiceField) 文件選項,目錄下文件顯示在頁面中
path, 文件夾路徑
match
=
None
, 正則匹配
recursive
=
False
, 遞歸下面的文件夾
allow_files
=
True
, 容許文件
allow_folders
=
False
, 容許文件夾
required
=
True
,
widget
=
None
,
label
=
None
,
initial
=
None
,
help_text
=
''
GenericIPAddressField
protocol
=
'both'
, both,ipv4,ipv6支持的IP格式
unpack_ipv4
=
False
解析ipv4地址,若是是::ffff:
192.0
.
2.1
時候,可解析爲
192.0
.
2.1
, PS:protocol必須爲both才能啓用
SlugField(CharField) 數字,字母,下劃線,減號(連字符)
...
UUIDField(CharField) uuid類型
...
|
二、Django內置插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
TextInput(
Input
)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
|
三、經常使用選擇插件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
# 單radio,值爲字符串
# user = fields.CharField(
# initial=2,
# widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
# 單radio,值爲字符串
# user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
# initial=2,
# widget=widgets.RadioSelect
# )
# 單select,值爲字符串
# user = fields.CharField(
# initial=2,
# widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
# 單select,值爲字符串
# user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
# initial=2,
# widget=widgets.Select
# )
# 多選select,值爲列表
# user = fields.MultipleChoiceField(
# choices=((1,'上海'),(2,'北京'),),
# initial=[1,],
# widget=widgets.SelectMultiple
# )
# 單checkbox
# user = fields.CharField(
# widget=widgets.CheckboxInput()
# )
# 多選checkbox,值爲列表
# user = fields.MultipleChoiceField(
# initial=[2, ],
# choices=((1, '上海'), (2, '北京'),),
# widget=widgets.CheckboxSelectMultiple
# )
|
展露頭角
單選或者多選時、數據源是否能夠實時更新、、、
在使用選擇標籤時,須要注意choices的選項能夠從數據庫中獲取,可是因爲是靜態字段 ***獲取的值沒法實時更新***,那麼須要自定義構造方法從而達到此目的。
方式1、
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
from
django.forms
import
Form
from
django.forms
import
widgets
from
django.forms
import
fields
from
django.core.validators
import
RegexValidator
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'].widget.choices = ((1, '上海'), (2, '北京'),)
# 或
self
.fields[
'user'
].widget.choices
=
models.Classes.objects.
all
().value_list(
'id'
,
'caption'
)
|
方式2、
使用django提供的ModelChoiceField和ModelMultipleChoiceField字段來實現
1
2
3
4
5
6
7
8
9
10
|
from
django
import
forms
from
django.forms
import
fields
from
django.forms
import
widgets
from
django.forms
import
models as form_model
from
django.core.exceptions
import
ValidationError
from
django.core.validators
import
RegexValidator
class
FInfo(forms.Form):
authors
=
form_model.ModelMultipleChoiceField(queryset
=
models.NNewType.objects.
all
())
# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
|
更上一層樓
經過上述,Django的Form組件提供驗證用戶提交的數據並能夠顯示錯誤信息(或自定製),更能能夠生成相應的Html代碼。更是猜測到,僅僅根據Form組件的驗證或許知足不了一些需求,因而創建再Form的驗證功能上使其有很強的擴展性
1、基於Form組件的字段上的簡單擴展
方式A
1
2
3
4
5
6
7
8
9
10
|
from
django.forms
import
Form
from
django.forms
import
widgets
from
django.forms
import
fields
from
django.core.validators
import
RegexValidator
class
MyForm(Form):
phone
=
fields.CharField(
validators
=
[RegexValidator(r
'^[0-9]+$'
,
'請輸入數字'
), RegexValidator(r
'^188[0-9]+$'
,
'數字必須以188開頭'
)],
)
|
方式B
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
import
re
from
django.forms
import
Form
from
django.forms
import
widgets
from
django.forms
import
fields
from
django.core.exceptions
import
ValidationError
# 自定義驗證規則
def
mobile_validate(value):
mobile_re
=
re.
compile
(r
'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$'
)
if
not
mobile_re.match(value):
raise
ValidationError(
'手機號碼格式錯誤'
)
class
PublishForm(Form):
title
=
fields.CharField(max_length
=
20
,
min_length
=
5
,
error_messages
=
{
'required'
:
'標題不能爲空'
,
'min_length'
:
'標題最少爲5個字符'
,
'max_length'
:
'標題最多爲20個字符'
},
widget
=
widgets.TextInput(attrs
=
{
'class'
:
"form-control"
,
'placeholder'
:
'標題5-20個字符'
}))
# 使用自定義驗證規則
phone
=
fields.CharField(validators
=
[mobile_validate, ],
error_messages
=
{
'required'
:
'手機不能爲空'
},
widget
=
widgets.TextInput(attrs
=
{
'class'
:
"form-control"
,
'placeholder'
: u
'手機號碼'
}))
email
=
fields.EmailField(required
=
False
,
error_messages
=
{
'required'
: u
'郵箱不能爲空'
,
'invalid'
: u
'郵箱格式錯誤'
},
widget
=
widgets.TextInput(attrs
=
{
'class'
:
"form-control"
,
'placeholder'
: u
'郵箱'
}))
|
2、基於源碼執行的流程上進行擴展
方式A
例如在註冊一個帳號時、經過Form的驗證其帳號符合規則時,還將要判斷該帳號是否存在於數據庫,如存在則確定是註冊不經過的
自定義方法、單一字段逐個再次驗證
from Formtest import models from django import forms from django.forms import fields from django.forms import widgets from django.core.exceptions import ValidationError,NON_FIELD_ERRORS from django.core.validators import RegexValidator class AjaxForm(forms.Form): user=fields.CharField( max_length=10, required=False, validators=[RegexValidator(r'^[a-z]+$', 'Enter a valid extension.', 'invalid')], ) email=fields.EmailField() def clean_user(self): """ Form中字段中定義的格式匹配完以後,執行此方法進行驗證 :return: """ v = self.cleaned_data['user'] if models.UserInfo.objects.filter(user=v).count(): raise ValidationError('此用戶名已經存在') return v def clean_email(self): """ email驗證過以後、能夠自定義驗證該郵箱是否被使用... :return: """ pass
方式B
from Formtest import models from django import forms from django.forms import fields from django.forms import widgets from django.core.exceptions import ValidationError,NON_FIELD_ERRORS from django.core.validators import RegexValidator class AjaxForm(forms.Form): user = fields.CharField( max_length=10, required=False, validators=[RegexValidator(r'^[a-z]+$', 'Enter a valid extension.', 'invalid')], ) email = fields.EmailField() def clean_user(self): """ Form中字段中定義的格式匹配完以後,執行此方法進行驗證 :return: """ v = self.cleaned_data['user'] if models.UserInfo.objects.filter(user=v).count(): raise ValidationError('此用戶名已經存在') return v def clean_email(self): """ email驗證過以後、能夠自定義驗證該郵箱是否被使用... :return: """ pass def clean(self): """ 在單字段自定義驗證完成以後、也能夠對總體進行一個驗證 :return: """ value_dict = self.cleaned_data user = value_dict.get('user') email = value_dict.get('email') if user == 'root' and email == 'root@163.com': raise ValidationError('身份驗證信息驗證失敗') return value_dict # ps: _post_clean是clean驗證完以後進一步驗證操做、通常用不到 # 全局錯誤信息地鍵是 __all__