介绍
我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息。Django的form组件就实现了上面所述的功能。
总结一下,其实form组件的主要功能如下:
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容
示例
通过下面注册示例感受一下普通方式和Form方式的差别。
普通HTML注册
1 from django.conf.urls import url 2 from test_app import views 3 4 urlpatterns = [ 5 url(r'^register_html/', views.register_html), 6 ]
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>注册</title> 6 </head> 7 <body> 8 <form action="/register_html/" method="post"> 9 {% csrf_token %} 10 <table> 11 <tr> 12 <td style="text-align: right">用户名:</td> 13 <td><input type="text" name="username" value="{{ username }}"></td> 14 <td style="color: red"> 15 {{ username_error }} 16 </td> 17 </tr> 18 <tr> 19 <td style="text-align: right">密码:</td> 20 <td><input type="password" name="userpwd" value="{{ userpwd }}"></td> 21 <td style="color: red">{{ userpwd_error }}</td> 22 </tr> 23 <tr> 24 <td style="text-align: right">确认密码:</td> 25 <td><input type="password" name="re_userpwd" value="{{ re_userpwd }}"></td> 26 <td style="color: red">{{ re_userpwd_error }}</td> 27 </tr> 28 <tr> 29 <td colspan="3" style="text-align: center"> 30 <input type="submit" value="提交"> 31 </td> 32 </tr> 33 </table> 34 </form> 35 </body> 36 </html>
1 from django.shortcuts import render, HttpResponse 2 3 4 def register_html(request): 5 if request.method == 'POST': 6 username = request.POST.get('username') 7 userpwd = request.POST.get('userpwd') 8 re_userpwd = request.POST.get('re_userpwd') 9 msg_dict = {'status': 'error', 'msg': '验证失败', 'username': username, 'userpwd': userpwd, 10 're_userpwd': re_userpwd} 11 # 限制用户名长度为6-12位 12 if len(username) < 6 or len(username) > 12: 13 msg_dict['username_error'] = '用户名长度需为6-12位' 14 print(msg_dict) 15 return render(request, 'register_html.html', msg_dict) 16 if len(userpwd) == 0: 17 msg_dict['userpwd_error'] = '密码不能为空' 18 return render(request, 'register_html.html', msg_dict) 19 # 确认两次输入密码一致 20 if userpwd != re_userpwd: 21 msg_dict['re_userpwd_error'] = '两次输入的密码必须一致' 22 return render(request, 'register_html.html', msg_dict) 23 # 上述验证都通过,下面执行注册操作 ... 24 return HttpResponse('注册成功') 25 return render(request, 'register_html.html')
Form组件注册
1 from django.conf.urls import url 2 from test_app import views 3 4 urlpatterns = [ 5 url(r'^register_form/', views.register_form), 6 ]
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>注册</title> 6 </head> 7 <body> 8 <form action="/register_form/" method="post" novalidate> 9 {% csrf_token %} 10 <table> 11 <tr> 12 <td style="text-align: right">{{ form_obj.username.label }}:</td> 13 <td>{{ form_obj.username }}</td> 14 <td style="color: red"> 15 {{ form_obj.username.errors.0 }} 16 </td> 17 </tr> 18 <tr> 19 <td style="text-align: right">{{ form_obj.userpwd.label }}:</td> 20 <td>{{ form_obj.userpwd }}</td> 21 <td style="color: red">{{ form_obj.userpwd.errors.0 }}</td> 22 </tr> 23 <tr> 24 <td style="text-align: right">{{ form_obj.re_userpwd.label }}:</td> 25 <td>{{ form_obj.re_userpwd }}</td> 26 <td style="color: red">{{ form_obj.re_userpwd.errors.0 }}</td> 27 </tr> 28 <tr> 29 <td colspan="3" style="text-align: center"> 30 <input type="submit" value="提交"> 31 </td> 32 </tr> 33 </table> 34 </form> 35 </body> 36 </html>
1 from django.shortcuts import render, HttpResponse 2 from django import forms 3 4 5 # 按照Django form组件的要求自己写一个类 6 class RegForm(forms.Form): 7 username = forms.CharField( 8 label="用户名", 9 min_length=6, 10 max_length=12, 11 initial="admin", 12 error_messages={ 13 "min_length": "用户名长度需为6-12位", 14 "max_length": "用户名长度需为6-12位", 15 } 16 ) 17 userpwd = forms.CharField( 18 label="密码", 19 required=True, 20 error_messages={ 21 "required": "密码不能为空", 22 }, 23 widget=forms.widgets.PasswordInput(render_value=True) 24 ) 25 re_userpwd = forms.CharField( 26 label="确认密码", 27 required=True, 28 error_messages={ 29 "required": "密码不能为空", 30 }, 31 widget=forms.widgets.PasswordInput(render_value=True) 32 ) 33 34 # 校验时会调用 35 def clean(self): 36 data = self.cleaned_data 37 userpwd = data.get('userpwd') 38 re_userpwd = data.get('re_userpwd') 39 if userpwd != re_userpwd: 40 self.add_error('re_userpwd', '两次输入的密码必须一致') 41 return data
Form字段
字段参数
-
required
指定某个字段是必需的。
from django import forms class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用户名", required=True ) pwd = forms.CharField(min_length=6, label="密码")
-
label
label参数用来指定页面中字段的标题,如果不指定,Field通过将字段名的所有下划线转换为空格和第一个字母的大写生成默认label。
from django import forms class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用户名", ) pwd = forms.CharField(min_length=6, label="密码")
-
label_suffix
给label指定后缀。
from django import forms class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用户名", label_suffix=':' ) pwd = forms.CharField(min_length=6, label="密码")
-
initial
给字段指定默认(初始)值。若要指定动态初始数据,请参见
Form.initial
参数。class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用户名", initial="张三" # 设置默认值 ) pwd = forms.CharField(min_length=6, label="密码")
-
widget
widget参数用于使用指定的Widget类来呈现Field(例如数字)。(小部件的更多信息)
-
help_text
help_text参数允许为Field指定描述性文本。如果提供help_text参数,它将显示在Field后。
from django import forms class LoginForm(forms.Form): username = forms.CharField( min_length=8, max_length=32, label="用户名", help_text='32 characters max.' ) pwd = forms.CharField(min_length=6, label="密码")
-
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="密码")
-
validators
validators参数允许为该字段提供验证函数的列表。(想了解更多信息见验证器文档)。
# 限定偶数验证器 from django import forms from django.core.exceptions import ValidationError def validate_even(value): print(value) if value % 2 != 0: raise ValidationError( '%(value)s is not an even number', params={'value': value}, ) class SimpleForm(forms.Form): even_field = forms.IntegerField(validators=[validate_even])
from django import forms from django.core.validators import RegexValidator class SimpleForm(forms.Form): phone_number = forms.CharField( validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]{8}$', '数字必须以159开头且11位')], )
-
localize
localize参数支持表单数据输入和呈现输出的本地化。(想了解更多信息见格式本地化文档)。
-
disable
该参数为布尔类型,设置为True,则禁用表单字段,使其不能被用户编辑。即使用户篡改了提交给服务器的字段的值,它也会被忽略。
常用内置字段
forms库附带了一组常见验证需求的Field类。本节记录一部分内置字段。想了解更多可参考Django官方文档。
对于每个字段,描述了不指定widget时使用的默认小部件类。还描述了在表单中提供空值时后台所对应的值(请参阅required了解这意味着什么)。
-
BooleanField
-
默认小部件
-
空时默认值
False
-
python类型
True或False
-
验证
值是否为
True(如果字段具有required=True)
例如,选中复选框。 -
错误信息键
required
-
注
因为
Field
类默认required=True。如果要在窗体中包含一个布尔值,可以选择True
或False
(例如选中或未选中复选框),必须记住传入required=False
创建BooleanField
.
-
-
CharField
-
默认小部件
-
空时默认值
-
python类型
字符串。
-
验证
max_length
或min_length
,如果提供的话。否则,所有输入都是有效的。 -
错误信息键
required
,max_length
,min_length
-
参数
- max_length
- min_length
-
如果提供了这些参数,则确保字符串最多或至少为给定长度。
- strip
-
如果True(默认),该值将被去掉前导和尾随空格。
-
-
ChoiceField
-
默认小部件
-
空时默认值
''
(空字符串) -
python类型
字符串。
-
验证
给定值是否存在于选项列表中。
-
错误信息键
required
,invalid_choice
-
参数
- choices
-
接收一个元组(列表)序列或返回该序列的函数句柄。
-
1 def choiceList(): 2 return [(1, '张三'), (2, '李四')] 3 4 5 class TestForm(forms.Form): 6 f1 = forms.ChoiceField(choices=choiceList) 7 f2 = forms.ChoiceField(choices=[(1, '张三'), (2, '李四')])
-
-
TypedChoiceField
-
默认小部件
-
空时默认值
-
python类型
由
coerce参数决定。
-
验证
给定值是否存在于选项列表中,并可强制执行。
-
错误信息键
required
,invalid_choice
-
参数
coerce
-
该参数接受一个函数,这个函数接受一个参数并返回一个的值作为cleaned_data中的值,而这个参数正是用户选择的值。返回值可以是
int
,float
,bool
以及其他类型。1 from django.shortcuts import render, HttpResponse 2 from django import forms 3 4 5 def choiceList(): 6 return [(1, '张三'), (2, '李四')] 7 8 9 def coerceFunc(value): 10 return ['选择的是{}'.format(tuple[1]) for tuple in choiceList() if tuple[0] == int(value)][0] 11 12 13 class TestForm(forms.Form): 14 f1 = forms.TypedChoiceField(choices=choiceList, coerce=coerceFunc) 15 16 17 def test(request): 18 form_obj = TestForm() 19 if request.method == 'POST': 20 form_obj = TestForm(request.POST) 21 if form_obj.is_valid(): 22 print(form_obj.cleaned_data.get('f1')) # 选择的是张三 23 24 return render(request, 'test.html', {'form_obj': form_obj})
-
-
DateField
-
默认小部件
-
空时默认值
None
-
python类型
datetime.date
-
验证
给定值是否为
datetime.date
,datetime.datetime
或以特定日期格式化的字符串。 -
错误信息键
required
,invalid
-
参数
- input_formats
-
用于尝试将字符串转换为有效的格式的列表。
datetime.date
对象。如果没有
input_formats
参数,默认输入格式如下:['%Y-%m-%d', # '2006-10-25' '%m/%d/%Y', # '10/25/2006' '%m/%d/%y'] # '10/25/06'
此外,如果指定
USE_L10N=False
在您的设置中,默认输入格式还将包括下列内容:['%b %d %Y', # 'Oct 25 2006' '%b %d, %Y', # 'Oct 25, 2006' '%d %b %Y', # '25 Oct 2006' '%d %b, %Y', # '25 Oct, 2006' '%B %d %Y', # 'October 25 2006' '%B %d, %Y', # 'October 25, 2006' '%d %B %Y', # '25 October 2006' '%d %B, %Y'] # '25 October, 2006'
另见格式本地化。
-
-
DateTimeField
-
默认小部件
-
空时默认值
None
-
python类型
datetime.datetime
-
验证
给定值是否为
datetime.datetime
,datetime.date
或以特定日期时间格式化的字符串。 -
错误信息键
required
,invalid
-
参数
- input_formats
-
用于尝试将字符串转换为
datetime.datetime
对象的有效的格式的列表。。如果没有
input_formats
参数,默认输入格式如下:['%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' '%Y-%m-%d %H:%M', # '2006-10-25 14:30' '%Y-%m-%d', # '2006-10-25' '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59' '%m/%d/%Y %H:%M', # '10/25/2006 14:30' '%m/%d/%Y', # '10/25/2006' '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59' '%m/%d/%y %H:%M', # '10/25/06 14:30' '%m/%d/%y'] # '10/25/06'
另见格式本地化.
-
-
DecimalField
-
默认小部件
localize=
False时为
NumberInput,localize=True时为
TextInput。
-
空时默认值
None
-
python类型
decimal
-
验证
给定值是否为十进制格式,前导和尾随空格会被忽略。
-
错误信息键
required
,invalid
,max_value
,min_value
,max_digits
,max_decimal_places
,max_whole_digits
-
参数
max_value和min_value错误消息可能包含%(limit_value)s,它将被适当的限制所取代。类似地,max_digits, max_decimal_places和max_whole_digits错误消息可能包含%(max)s.
- min_value
- max_value
-
控制字段中允许值的范围(最小值和最大值)。
- max_digits
-
值中允许的最大数字数(小数点之前的数字加上小数点之后的数字,并去掉前导零)。
- decimal_places
-
允许的最大小数位数。
-
-
DurationField
-
默认小部件
-
空时默认值
None
-
python类型
-
验证
给定值是否为可转换为
timedelta。
-
错误信息键
required
,invalid
-
注
接收任何可通过
parse_duration()转换的值。
-
-
EmailField
-
默认小部件
-
空时默认值
''
(空字符串) -
python类型
字符串
-
验证
使用一个中等复杂的正则表达式验证给定的值是否是一个有效的电子邮件地址。
-
错误信息键
required
,invalid
-
参数
有两个用于验证的可选参数,max_length和min_length。如果提供了这些参数,则确保字符串最多或至少为给定长度。
-
-
FileField
-
默认小部件
-
空时默认值
None
-
python类型
UploadedFile
对象,该对象将文件内容和文件名包装到单个对象中。 -
验证
非空文件数据是否已绑定到控件。
-
错误信息键
required
,invalid
,missing
,empty
,max_length
-
参数
有两个用于验证的可选参数,max_length和allow_empty_file。如果提供,则确保文件名最多为给定长度,即使文件内容为空,验证也将成功。
想了解更多关于
UploadedFile
对象,请参阅文件上载文档。当你在form中使用
FileField时
,还必须记住将文件数据绑定到窗体.max_length
是指文件名的长度。在该键的错误消息中,%(max)d
将被替换为最大文件名长度和%(length)d
将被替换为当前文件名长度。
-
-
FilePathField
-
默认小部件
-
空时默认值
None
-
python类型
字符串
-
验证
所选项是否存在于选项列表中。
-
错误信息键
required
,invalid_choice
-
参数
- path
-
其内容所在目录的绝对路径。这个目录必须存在。
- recursive
-
如果是
False,
直接将path下内容提供作为选择。如果True
,目录将被递归地将所有的后代作为选择列出。
-
正则表达式模式,只有具有与此表达式匹配的名称的文件才允许作为选择。
-
可选的。
True
或False
。默认值是True
。指定是否包括指定位置中的文件。如果这个是False那么allow_folders
一定是True。
-
可选的。
True
或False
。默认值是False
。指定是否应包括指定位置中的文件夹。如果这个是False那么allow_files
一定是True
.
-
-
FloatField
-
ImageField
-
默认小部件
-
空时默认值
None
-
python类型
UploadedFile
对象,该对象将文件内容和文件名包装到单个对象中。 -
验证
文件数据是否已绑定到表单,并且该文件是否具有由Pillow可解析的图像格式。
-
错误信息键
required
,invalid
,missing
,empty
,invalid_image
-
参数
要使用ImageField,要求已安装的Pillow支持该格式。
如果在上传的时候遇到corrupt image error,这通常表示Pillow不能解析该格式。要解决这个问题,请安装适当的库并重新安装Pillow。
当在表单上使用
ImageField时
,还必须记住将文件数据绑定到窗体。在清理和验证字段后,
UploadedFile
对象将有一个额外image属性,它包含Pillow的image实例,用于检查文件是否为有效图像。还有,UploadedFile.content_type
将被更新为图像的内容类型,前提是Pillow可以解析它,否则它将被设置为None
.
-
-
IntegerField
-
GenericIPAddressField
-
默认小部件
-
空时默认值
''
(空字符串) -
python类型
字符串
-
验证
给定值是否为有效的IP地址。
-
错误信息键
required
,invalid
-
参数
- protocol
-
限制指定协议的有效输入,默认值是
both
,IPv4
或IPv6
。匹配是不区分大小写的。 - unpack_ipv4
-
解包IPv 4映射地址,如
::ffff:192.0.2.1
。如果启用此选项,该地址将解压缩到192.0.2.1
。默认值为禁用。只能在protocol
设置为'both'时使用。
.
-
-
MultipleChoiceField
-
默认小部件
-
空时默认值
[]
(空list) -
python类型
字符串列表
-
验证
给定值列表中的每个值是否存在于选项列表中。
-
错误信息键
required
,invalid_choice
,invalid_list
-
参数
invalid_choice错误信息可能包含%(value)s,它将被选定的选项替换。
- choices
-
相对
ChoiceField
来说该参数在这里是必选的。
-
-
TypedMultipleChoiceField
-
默认小部件
-
空时默认值
empty_value
-
python类型
由coerce参数决定
-
验证
给定值是否存在于选项列表中,并可强制执行。
-
错误信息键
required
,invalid_choice
-
参数
invalid_choice错误信息可能包含%(value)s,它将被选定的选项替换。
- coerce
- empty_value
-
-
NullBooleanField
-
默认小部件
-
空时默认值
None
-
python类型
False、True或None。
-
验证
任何内容(即,它从不引发
ValidationError
)。
-
-
RegexField
-
默认小部件
-
空时默认值
''
(空字符串) -
python类型
字符串。
-
验证
给定值是否与某个正则表达式匹配。
-
错误信息键
required
,invalid
-
参数
- Regex
-
指定为字符串类型正则表达式或编译后的正则表达式对象。
- strip
-
默认为
False
。如果启用,将在regex验证之前去除前后空格。
-
-
slugField
-
默认小部件
-
空时默认值
''
(空字符串) -
python类型
字符串。
-
验证
给定的值只包含字母、数字、下划线和连字符。
-
错误信息键
required
,invalid
-
参数
- allow_unicode
-
指示字段除接受ASCII字母之外还接受Unicode字母的布尔值,默认为
False。
- 参数名
-
参数说明
-
-
TimeField
-
默认小部件
-
空时默认值
None
-
python类型
datetime.time
-
验证
给定值是否为
datetime.time
或以特定时间格式化的字符串。 -
错误信息键
required
,invalid
-
参数
- input_formats
-
用于尝试将字符串转换为
datetime.time
对象的有效的格式的列表。如果没有input_formats参数,默认输入格式如下:
'%H:%M:%S', # '14:30:59' '%H:%M', # '14:30'
-
-
URLField
-
默认小部件
-
空时默认值
''
(空字符串) -
python类型
字符串
-
验证
给定值是否为有效URL。
-
错误信息键
required
,invalid
-
参数
- max_length
- min_length
-
控制输入长度范围。
-
-
UUIDField
ModelForm
使用
from django.db import models class UserInfo(models.Model): name =models.CharField(max_length=32) password = models.CharField(max_length=20) age = models.IntegerField() sex = models.IntegerField(choices=((1,'男'),(0,'女')))
from django import forms from app import models class UserForm(forms.ModelForm): class Meta: model = models.UserInfo fields = '__all__' labels = { "name": "用户名", "sex": "性别", 'age':'年龄', 'password':'密码' } widgets = { "password": forms.widgets.PasswordInput(attrs={"class": "c1"}), }
参数说明
ModelForm类中Meta类下常用字段说明:
model = models.UserInfo # 对应的Model中的类 fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段,也可以是一个需要渲染的字段名列表。 exclude = None # 排除的字段 labels = None # 提示信息 help_texts = None # 帮助提示信息 widgets = None # 自定义插件 error_messages = None # 自定义错误信息
补充
常用小部件
-
Textarea
多行文本框。from django import forms class CommentForm(forms.Form): comment = forms.CharField(widget=forms.Textarea)
效果: -
SelectDateWidget
拆分日期框。class SimpleForm(forms.Form): birth_year = forms.DateField(widget=forms.SelectDateWidget(years=('1980', '1981', '1982')))
效果: -
CheckboxSelectMultiple
多选勾选框。from django import forms class SimpleForm(forms.Form): favorite_colors = forms.MultipleChoiceField( widget=forms.CheckboxSelectMultiple, choices=( ('blue', 'Blue'), ('green', 'Green'), ('black', 'Black'), ) )
效果: -
RadioSelect
单选按钮。from django import forms class SimpleForm(forms.Form): choice_field = forms.ChoiceField(widget=forms.RadioSelect, choices=(('1', 'First',), ('2', 'Second',)))
效果: -
TextInput
普通文本输入框。from django import forms class SimpleForm(forms.Form): # CharField字段默认小部件就是TextInput,所以指定和不指定的效果是一样的。 name = forms.CharField(widget=forms.TextInput())
效果: -
Select
单选下拉框。from django import forms class SimpleForm(forms.Form): hobby = forms.fields.ChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=3, widget=forms.widgets.Select() )
效果: -
SelectMultiple
多选下拉框。from django import forms class SimpleForm(forms.Form): hobby = forms.fields.MultipleChoiceField( choices=((1, "篮球"), (2, "足球"), (3, "双色球"),), label="爱好", initial=[1, 3], widget=forms.widgets.SelectMultiple() )
效果: -
CheckboxInput
单选勾选框。
from django import forms class SimpleForm(forms.Form): keep = forms.fields.ChoiceField( label="是否记住密码", initial="checked", widget=forms.widgets.CheckboxInput() )
效果:
可以通过attrs来给小部件指定展示时的属性:
from django import forms name = forms.TextInput(attrs={'size': 10, 'title': 'Your name'}) name.render('name', 'A name') '<input title="Your name" type="text" name="name" value="A name" size="10" />'
批量添加样式
可通过重写form类的__init__方法实现。
class LoginForm(forms.Form): username = forms.CharField( min_length=8, label="用户名", initial="张三", error_messages={ "required": "不能为空", "invalid": "格式错误", "min_length": "用户名最短8位" } ... def __init__(self, *args, **kwargs): super(LoginForm, self).__init__(*args, **kwargs) for field in iter(self.fields): self.fields[field].widget.attrs.update({ 'class': 'form-control' })