Forms组件
forms组件前戏
题目:写一个注册功能,获取用户名和密码 利用form表单提交数据,在后端判断用户名和密码是否符合一定的条件:用户名中不能含有xxx,密码不能少于三位。如果不符合条件需要你将提示信息展示到前端页面
思路:在前端页面的input标签后面加上和两个span标签,标签里面放上后端传回的信息,后端代码里面分别对提交的用户名和密码信息进行验证,讲验证之后的信息添加到已经封装好的字典中。
{#前端代码#}
<form action="" method="post">
<p>
用户名:<input type="text" name="username">
<span style="color: red">{{ back_dict.username }}</span>
</p>
<p>
密码:<input type="password" name="password">
<span style="color: red">{{ back_dict.password }}</span>
</p>
<p><input type="submit" value="提交"></p>
</form>
#后端代码
def index(request):
back_dict = {'username':'','password':''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if 'xxx' in username:
back_dict['username'] = '不符合社会主义核心价值观'
if len(password)<3:
back_dict['password'] = '密码不能小于三位数'
return render(request,'index.html',locals())
在这次说明一下,在实际项目中是必须要在后端对用户输入的数据进行校验,因为前端代码可以直接修改,利用爬虫等程序可以轻松绕过前端的验证,后端对用户输入的数据必须进行一个校验。
利用上述代码代码进行校验太low了,如何利用forms组件进行校验呢?
forms组件能够完成的事情:1.渲染html代码 2.校验数据 3.展示提示信息
接下来讲一下
forms组件的基本使用:
写在views视图文件中:先导入forms模块,新建一个类,属性的字段参数中常见的有:label:字段名(对应前端页面中input标签前面的解释,用户名,密码等等),error_messages :自定义报错信息,required:控制字段是否为必填字段
from django import forms
class MyForm(forms.Form):
#定义username字符串类型最小3位最大8位
username = forms.CharField(min_length=3,max_length=8,label='用户名',initial='David',
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 = forms.EmailField(error_messages={
'invalid':'邮箱格式不正确',
'required': "邮箱不能为空",
},label='邮箱',required=True,
)
在python console中可以对定义的报错信息进行初始校验,方法如下:
from app01 import views
#1 实例化一个类对象,将带校验的数据组织成字典的形式传入
form_obj = views.MyForm({'username':'jason','password':'123','email':'123'})
#2 判断数据是否合法,该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid()
False
#3 在完成判断数据是否合法之后,可以查看所有校验通过的数据(注意:这个方法只有在判断数据是否合法之后才能有的方法,如果未进行第二步的校验,无没有该方法)
form_obj.cleaned_data
{'username': 'jason', 'password': '123'}
#4 查看所有不符合校验规则以及不符合的原因
form_obj.errors
{
'email': ['Enter a valid email address.']
}
# 5 校验数据只校验类中出现的字段 多传不影响 多传的字段直接忽略,例如:
form_obj = views.MyForm({'username':'jason','password':'123','email':'123@qq.com','hobby':'study'})
form_obj.is_valid()
True
# 6 校验数据 默认情况下 类里面所有的字段都必须传值(默认数据可以多传,不能少传)
form_obj = views.MyForm({'username':'jason','password':'123'}) form_obj.is_valid()
False
在后端定义了需要验证的字段之后,不需要在前端页面中重新书写标签代码,可以直接在前端对标签进行渲染:
三种渲染方式
#后端代码 views.py
def ab_form(request):
#1.先实例化一个组件类空对象
form_obj = MyForm()
#2 直接将该空对象传递给后端页面
return render(request,'ab_form.html',locals())
{#前端代码 ab_form.html#}
<body>
{#<p>第一种渲染方式:代码书写极少,封装程度太高 不便于后续的扩展 一般情况下只在本地测试使用</p>#}
{# {{ form_obj.as_p }}#}
{# {{ form_obj.as_ul }}#}
{# {{ form_obj.as_table }}#}
{#<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>第三种渲染方式(推荐使用):代码书写简单 并且扩展性也高</p>
{% for form in form_obj %}
<p>{{ form.label }}:{{ form }}</p>
{% endfor %}
</body>
渲染好了标签之后,如何将验证信息反馈在前端页面呢?首先,浏览器会自动帮你校验数据,但是前端的校验弱不禁风,但是你如果不做校验呢?可以给form表单加一个novalidate属性
<form action="" method="post" novalidate>
如果标签是渲染出来的如何进行展示校验信息呢?
#后端代码
def ab_form(request):
#1.先实例化一个组件类空对象
form_obj = MyForm()
if request.method == 'POST':
#首先获取用户数据并进行校验,从面前对报错信息进行验证分析可以知道,被校验数据需要构造成字典传入才行,request.POST获得的数据就可以看成是一个字典
#3校验数据
form_obj = MyForm(request.POST)
#必须先判断数据是否合法
if form_obj.is_valid():
#5 如果合法,接下来进行数据库操作,存入数据
return HttpResponse('OK')
#5 不合法,有错误,这里什么也不需要写,直接走后面的代码,将form_obj传回去
#2 直接将该空对象传递给后端页面
return render(request,'ab_form.html',locals())
{% for form in form_obj %}
<p>
{{ form.label }}:{{ form }}
{#此时form_obj中已经包含前面传回来的错误信息了,可以直接用,参考前面说过的对错误信息校验#}
<span style="color: red">{{ form.errors.0 }}</span>
</p>
{% endfor %}
注意点:1.必备的条件 get请求和post传给html页面对象变量名必须一样,因为post请求过来进行校验之后如果有错误信息相当于将页面刷新,不一样的话之前,一开始get请求时候的代码就没办法用了
2.forms组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改,更加人性化
在这里补充一点内容:如果没有指定错误信息的话,错误信息提示是英文的,可以通过指定错误信息来对需要展示的错误信息进行修改。修改后的错误信息就是放在上面的error_messages字段参数中,以字典的形式表示出来
钩子函数:在特定的节点自动触发完成响应操作,钩子函数在forms组件中就类似于第二道关卡,能够让我们自定义校验规则
在forms组件中有两类钩子:
1.局部钩子
当你需要给单个字段增加校验规则的时候可以使用
2.全局钩子
当你需要给多个字段增加校验规则的时候可以使用
实际案例:1.校验用户名中不能含有xxx 只是校验某一个字段,使用局部钩子 2.校验密码和确认密码是否一致,需要对比password和confirm_password两个字段,需要用到全局钩子
需要用到钩子函数的时候,直接在类里面直接书写钩子函数即可
# 局部钩子
def clean_username(self):
# 获取到用户名
username = self.cleaned_data.get('username')
if '666' in username:
# 提示前端展示错误信息
self.add_error('username','光喊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
常见的参数有:
label 字段名
error_messages 自定义报错信息
initial 默认值,对应input框中的value属性
required 控制字段是否必填
如果字段没有样式,如何针对不同类型的input进行操作修改?text password date radio checkbox等标签属性
要给哪个标签添加属性就在相应的组件类下面的属性参数里面添加
eg:
#在组件类下面password属性下面添加如下代码,表示给该标签加上一个password属性,后面表示增加一个class属性,其他的不同样式用空格隔开
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})
给
在对手机号码进行校验的时候经常用到正则校验
#先导入校验模块
from django.core.validators import RegexValidator
然后在定义好的forms组件类里面添加正则校验参数
phone = forms.CharField(
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
],
其他类型渲染:不需要死记硬背,需要用的时候过来看一下,直接拿过去用
# radio
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
)
# select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
# 多选
hobby1 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
# 单选checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
# 多选checkbox
hobby2 = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
浙公网安备 33010602011771号