目录
- forms组件
- forms组件类书写
- forms组件如何校验数据
- forms组件如何渲染标签
- forms组件展示错误信息
- forms组件钩子函数(HOOK)
- forms组件常见参数
- forms组件源码
1、forms组件
小示例:
写一个注册功能:
利用form表单提交数据,获取用户名密码,在后端判断用户名密码是否符合条件:用户名不能包含abc字符串,密码不能少于6位数。
views.py文件:
from django.shortcuts import render
# Create your views here.
def ab_form(request):
back_dic = {'username':'','password':''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if 'abc' in username:
back_dic['username'] = '用户名不能包含字符串abc'
if len(password)<6:
back_dic['password'] = '密码必须为6位数'
# back_dic字典值默认是空,当用户输入用户名密码并提交时,就发起了post请求,back_dic通过校验如果不符合要求就会传值
return render(request,'ab_form.html',locals())
html页面:
<body>
<form action="" method="post">
<p>username:
<input type="text" name="username">
<span style="color: red">{{ back_dic.username }}</span>
</p>
<p>password:
<input type="password" name="password">
<span style="color: red">{{ back_dic.password }}</span>
</p>
<input type="submit" class="btn btn-info" value="submit">
</form>
</body>
以上我们就手动完成了需求:
1、书写前端获取用户数据的HTML代码
2、后端对用户数据进行校验
3、对不符合要求的数据进行前端提示
实际上以上功能form组件都能完成(渲染代码、校验数据、前端展示提示)。
应用场景:例如博客园的注册页面
数据校验前端可有可无,但是后端必须要有!因为前端的校验你可以直接修改,或者利用爬虫程序绕过前端页面直接朝后端提交数据。
2、forms组件类书写
views.py文件中:
from django import forms
class MyForm(forms.Form):
# username,password这两个字段最少3位数,最大8位数
username = forms.CharField(min_length=3,max_length=8)
password = forms.CharField(min_length=3,max_length=8)
# email字段必须符合邮箱格式,xx@xx.com
email = forms.EmailField()
3、forms组件如何校验数据
测试环境的准备除了我们之前用的tests.py,在pycharm里面已经给我们提供了一个Django的测试环境:点击Python Console:
校验步骤:
1、将要校验的数据组织成形式传入
2、判断数据是否合法,is_valid()方法用来校验我们传入的字典数据是否合法,该方法只有在所有的数据全部合法的情况下才会返回True
3、cleaned_data拿到所有符合条件的数据;
4、errors拿到所有不符合校验规则的数据以及不符合规则的原因,以键值对的形式展现,并且值是以列表的形式,因为一个字段有可能会不符合多个规则。
如果我再多传入一个hobby键:
form_obj = views.MyForm({'username':'jack','password':'12','email':'123','hobby':'study'})那么hobby是不会被校验的,只会找MyForm类里面书写的字段去做校验,而hobby不会被放到cleaned_data也不会被放到errors中。
默认情况下,类里面的所有字段都必须传值。如果少传了一个键,少传的那个字段会被放到errors中:
form_obj = views.MyForm({'username':'jack','password':'123'})
form_obj.errors
{'email': ['This field is required.']}
form_obj.cleaned_data
{'username': 'jack', 'password': '123'}
4、forms组件如何渲染标签
结合form组件获取用户注册的用户名密码邮箱,有了form组件之后所有获取用户输入的标签都不需要自己写了。form组件不会帮你渲染提交按钮,要自己添加。
views.py文件:
from django import forms
class MyForm(forms.Form):
# username,password这两个字段最少3位数,最大8位数
username = forms.CharField(min_length=3,max_length=8,label='用户名')
password = forms.CharField(min_length=3,max_length=8,label='密码')
# email字段必须符合邮箱格式,xx@xx.com
email = forms.EmailField(label='邮箱')
def index(request):
# 1、先产生一个空对象
form_obj = MyForm()
# 2、直接将该空对象传递给HTML页面
return render(request,'index.html',locals())
前端index.html页面(前端对生成的空对象做操作):
label属性默认展示的是类中字段首字母大写的形式,也可以修改:通过给字段加label属性。
<body>
<form action="" method="post">
<p>第一种form表单渲染方式:</p>
<p>代码书写极少,封装程度太高,不利于后续的扩展,一般只在本地测试使用</p>
<p>as_p</p>
{{ form_obj.as_p }}
<p>as_ul</p>
{{ form_obj.as_ul }}
<p>as_table</p>
{{ form_obj.as_table }}
<p>第二种form表单渲染方式:</p>
<p>可扩展性强,但是需要书写的代码太多,一般不用</p>
<p>{{ form_obj.username.label }} :{{ form_obj.username }}</p>
<p>{{ form_obj.password.label }} :{{ form_obj.password }}</p>
<p>{{ form_obj.email.label }} :{{ form_obj.email }}</p>
<p>第三种form表单渲染方式:</p>
<p>代码书写简单,扩展性高,推荐使用</p>
{% for form in form_obj %}
<p> {{ form.label }} :{{ form }} </p>
{% endfor %}
</form>
</body>
5、forms组件展示错误信息
浏览器会自动帮你做校验(如下图的提示信息),但是前端的校验还是不安全,我们可以给form表单加个参数取消前端浏览器自动校验功能:<form action="" method="post" novalidate>
form表单展示错误信息需要注意:
1、get请求和post请求传给页面的对象变量名必须一致form_obj
2、当你的数据不合法时,form组件会保存你输入的数据,让你基于上次的输入数据进行修改,更加人性化
views.py文件
from django import forms
class MyForm(forms.Form):
# username,password这两个字段最少3位数,最大8位数
username = forms.CharField(min_length=3,max_length=8,label='用户名',
error_messages={
'min_length':'用户名最少3位',
'max_length':'用户名最多8位',
'required':'用户名不能为空'
})
password = forms.CharField(min_length=3,max_length=8,label='密码',
error_messages={
'min_length': '密码最少3位',
'max_length': '密码最多8位',
'required': '密码不能为空'
})
# email字段必须符合邮箱格式,xx@xx.com
email = forms.EmailField(label='邮箱',
error_messages={
'invalid':'邮箱格式不正确',
'required': '邮箱不能为空'
})
def index(request):
# 1、先产生一个空对象
form_obj = MyForm()
if request.method == 'POST':
# 3、校验数据
form_obj = MyForm(request.POST)
# 4、判断数据是否合法
if form_obj.is_valid():
# 5、如果合法,操作数据库存储数据
return HttpResponse('OK')
# 5、如果不合法,将错误信息展示到前端
# 2、直接将该空对象传递给HTML页面
return render(request,'index.html',locals())
index.html页面:
<body>
<form action="" method="post" novalidate>
{% for form in form_obj %}
<p> {{ form.label }} :{{ form }}
{# form.errors.0这后面加了一个.0表示只拿列表第一个错误信息,就不会自动帮你生成ul标签 #}
<span style="color:red">{{ form.errors.0 }}</span>
</p>
{% endfor %}
<button>提交</button>
</form>
</body>
在给字段添加了error_messages参数之后,错误提示就变成自己输入的了(自定义)。
6、forms组件钩子函数
钩子函数:在特定的节点自动触发完成响应操作
在form组件中有两类钩子
1、局部钩子
当你需要给某个字段增加校验规则的时候可以使用,在后端校验的基础上进行二次校验。
2、全局钩子
当你需要给多个字段增加校验规则的时候可以使用。
实际案例:
1、校验用户名中不能包含666(只需要校验用户名,可以用局部钩子)
2、校验密码和确认密码是否一致(校验密码字段和确认密码字段,需要用全部钩子)
views.py文件做如下修改:
from django import forms
class MyForm(forms.Form):
# username,password这两个字段最少3位数,最大8位数
username = forms.CharField(min_length=3,max_length=8,label='用户名',
error_messages={
'min_length':'用户名最少3位',
'max_length':'用户名最多8位',
'required':'用户名不能为空'
})
password = forms.CharField(min_length=3,max_length=8,label='密码',
error_messages={
'min_length': '密码最少3位',
'max_length': '密码最多8位',
'required': '密码不能为空'
})
confirm_password = forms.CharField(min_length=3,max_length=8,label='确认密码',
error_messages={
'min_length': '密码最少3位',
'max_length': '密码最多8位',
'required': '密码不能为空'
})
# email字段必须符合邮箱格式,xx@xx.com
email = forms.EmailField(label='邮箱',
error_messages={
'invalid':'邮箱格式不正确',
'required': '邮箱不能为空'
})
# 局部钩子
def clean_username(self):
# 获取用户名
username = self.cleaned_data.get('username')
if '666' in username:
# 提示前端展示错误信息
# 提示方式1:
self.add_error('username','用户名不能包含666')
# 提示方式2(繁琐,一般不用):
# raise ValidationError('用户名不能包含666.')
# 将钩子函数钩取出来的数据再放回去
return username
# 全局钩子
def clean(self):
# 获取两个密码字段
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not confirm_password == password:
self.add_error('confirm_password','两次密码不一致')
# 校验后将全局钩子钩出来的数据再放回去
return self.cleaned_data
7、forms组件常见参数
label='用户名',设置字段名
error_messages={'min_length': '密码最少3位',},自定义报错信息
initial='jack',默认值
required=False,设置成必填字段
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'}),调整样式(多个属性值用空格隔开即可)
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.CharField(validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
),支持字段写正则表达式,可以写多个正则一一匹配
其他类型渲染:Django Form表单组件 - JasonJi - 博客园www.cnblogs.com
radiocheckboxselect
class LoginForm(forms.Form):
...
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
针对字段的校验方式:
1、最简单的max_length,min_length
2、正则validator
3、钩子函数
8、forms组件源码
切入点:form_obj.is_valid()
def is_valid(self):
"""
Returns True if the form has no errors. Otherwise, False. If errors are
being ignored, returns False.
"""
return self.is_bound and not self.errors
# 如果is_valid要返回true的话,那么self.is_bound要为true,self.errors要为false
# self.is_bound = data is not None or files is not None
# 所以只要你传数据了,那么self.is_bound就是true
@property
def errors(self):
"Returns an ErrorDict for the data provided for the form"
if self._errors is None:
self.full_clean()
return self._errors
# forms组件所有功能基本都出自于该方法:
def full_clean(self):
self._clean_fields() # 校验字段+局部钩子
self._clean_form() # 全局钩子
self._post_clean()