form表单是前端向后端提交用户数据时经常使用的标签,用户在利用form进行数据提交的时候通常需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示显示对应的错误信息。
而对于数据校验的部分由开发人员自己实现有时会显得多余繁琐,所以利用Django内置的Form表单就很好的封装了数据校验等实用功能。
总结一下,其实form组件的主要功能如下:
生成页面可用的HTML标签对用户提交的数据进行校验保留上次输入内容
普通Form对注册信息进行验证
from django.conf.urls
import url
from app01
import views
urlpatterns = [
url(
r'^normal_register', views.normal_register),
]
from django.shortcuts
import render, HttpResponse
def normal_register(request):
def normal_register(request):
if request.method ==
'POST':
uname = request.POST.get(
'username')
pword = request.POST.get(
'password')
if len(uname) <
6:
return render(request,
"normal_register.html", {
"username_error":
"用户名不能小于6位"})
return HttpResponse(
'<h2>注册信息通过验证!</h2>')
return render(request,
"normal_register.html")
<!DOCTYPE html>
<html lang=
"en">
<head>
<meta charset=
"utf-8">
<meta http-equiv=
"X-UA-Compatible" content=
"IE=edge">
<meta name=
"viewport" content=
"width=device-width, initial-scale=1">
<!-- 上述
3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<link href=
"https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel=
"stylesheet">
<title>普通Form注册</title>
</head>
<body>
<form action=
"/normal_register/" method=
"post">
{% csrf_token %}
<div>
<label
for=
"user_name">用户名:</label>
<input type=
"text" name=
"username" id=
"user_name">
<span>{{ username_error }}</span>
</div>
<div>
<label
for=
"pwd">密码:</label>
<input type=
"password" name=
"password" id=
"pwd">
</div>
<input type=
"submit" value=
"注册">
</form>
<!-- jQuery (necessary
for Bootstrap
's JavaScript plugins) -->
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
Django Form对注册信息进行验证
from django.conf.urls
import url
from app01
import views
urlpatterns = [
url(
r'^django_from_register/', views.django_from_register),
]
from django.shortcuts
import render, HttpResponse
from django
import forms
class DjangoFromRegister(forms.Form):
username = forms.CharField(
label=
'用户名',
label_suffix=
'::',
min_length=
6,
max_length=
32,
error_messages={
'required':
'这是必填项',
'min_length':
'用户名长度必须大于6个字符!',
'max_length':
'用户名长度必须小于32个字符',
},
)
password = forms.CharField(
label=
'密码',
label_suffix=
'::',
widget=forms.widgets.PasswordInput(),
error_messages={
'required':
'这是必填项',
},
)
def django_from_register(request):
form_obj = DjangoFromRegister()
if request.method ==
'POST':
form_obj = DjangoFromRegister(request.POST)
if form_obj.is_valid():
uname = form_obj.cleaned_data.get(
'username')
pword = form_obj.cleaned_data.get(
'password')
return HttpResponse(
'<h2>Django_Form:注册信息通过验证!</h2>')
print(
'这是错误信息的列表:',form_obj.errors)
return render(request,
"django_from_register.html", {
"form_obj": form_obj})
<!DOCTYPE html>
<html lang=
"en">
<head>
<meta charset=
"utf-8">
<meta http-equiv=
"X-UA-Compatible" content=
"IE=edge">
<meta name=
"viewport" content=
"width=device-width, initial-scale=1">
<!-- 上述
3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<link href=
"https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel=
"stylesheet">
<title>Django Form注册</title>
</head>
<body>
<form action=
"/django_from_register/" method=
"post" novalidate>
{% csrf_token %}
<div>
<label
for=
"{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
{{ form_obj.username }}
<span>{{ form_obj.username.errors
.0 }}</span>
</div>
<div>
<label
for=
"{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label>
{{ form_obj.password }}
<span>{{ form_obj.password.errors
.0 }}</span>
</div>
<input type=
"submit" value=
"注册">
</form>
<!-- jQuery (necessary
for Bootstrap
's JavaScript plugins) -->
<script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
3、常用字段介绍
initial
初始值,input框里面的初始值
class LoginForm(forms.Form):
username = forms.CharField(
min_length=
8,
label=
"用户名",
initial=
"张三"
)
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=
"密码")
password
input框的type转换为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.fields.ChoiceField(
choices=((
1,
"篮球"), (
2,
"足球"), (
3,
"双色球"), ),
label=
"爱好",
initial=
3,
widget=forms.widgets.Select
)
多选Select
多选的选择框
class LoginForm(forms.Form):
...
hobby = forms.fields.MultipleChoiceField(
choices=((
1,
"篮球"), (
2,
"足球"), (
3,
"双色球"), ),
label=
"爱好",
initial=[
1,
3],
widget=forms.widgets.SelectMultiple
)
单选checkbox
单选下拉框
class LoginForm(forms.Form):
...
keep = forms.fields.ChoiceField(
label=
"是否记住密码",
initial=
"checked",
widget=forms.widgets.CheckboxInput
)
多选checkbox
多选下拉框
class LoginForm(forms.Form):
...
hobby = forms.fields.MultipleChoiceField(
choices=((
1,
"篮球"), (
2,
"足球"), (
3,
"双色球"),),
label=
"爱好",
initial=[
1,
3],
widget=forms.widgets.CheckboxSelectMultiple
)
关于choice的注意事项
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 获取的值无法实时更新,那么需要自定义构造方法从而达到此目的。
from django.forms
import Form
from django.forms
import widgets
from django.forms
import fields
class MyForm(Form):
user = fields.ChoiceField(
initial=
2,
widget=widgets.Select
)
def __init__(self, *args, **kwargs):
super(MyForm,self).__init__(*args, **kwargs)
self.fields[
'user'].widget.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())
补充:Django Form内置字段
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,
limit_choices_to=
None
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类型
★4、校验
方式一
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.CharField(
validators=[RegexValidator(
r'^[0-9]+$',
'请输入数字'), RegexValidator(
r'^159[0-9]+$',
'数字必须以159开头')],
)
方式二
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'邮箱'}))
5、进阶操作
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
<title>login
</title>
</head>
<body>
<div class="container">
<div class="row">
<form action="/login2/" method="post" novalidate class="form-horizontal">
{% csrf_token %}
<div class="form-group">
<label for="{{ form_obj.username.id_for_label }}"
class="col-md-2 control-label">{{ form_obj.username.label }}
</label>
<div class="col-md-10">
{{ form_obj.username }}
<span class="help-block">{{ form_obj.username.errors.0 }}
</span>
</div>
</div>
<div class="form-group">
<label for="{{ form_obj.pwd.id_for_label }}" class="col-md-2 control-label">{{ form_obj.pwd.label }}
</label>
<div class="col-md-10">
{{ form_obj.pwd }}
<span class="help-block">{{ form_obj.pwd.errors.0 }}
</span>
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">{{ form_obj.gender.label }}
</label>
<div class="col-md-10">
<div class="radio">
{% for radio in form_obj.gender %}
<label for="{{ radio.id_for_label }}">
{{ radio.tag }}{{ radio.choice_label }}
</label>
{% endfor %}
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-default">注册
</button>
</div>
</div>
</form>
</div>
</div>
<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
</body>
</html>
5.2 批量添加样式
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'
})
urls.py配置关系映射views.py中创建Form类,定义字段的校验条件,在映射关系中实例化Form类,进行逻辑处理,将Form对象通过响应Response返回页面中页面中调用实例化Form对象进行操作
7、官方链接
https://docs.djangoproject.com/en/1.11/ref/forms/