在写django模板的表单内容时,有三种疑问:
- 每个输入框都要手写相当麻烦, 如何简便优化
- 用户的输入内容如何校验
- 校验出错了,又如何告知用户
而这些django的form组件都能很好的解决。
后端校验的重要性
因为前段页面内容展现在浏览器,用户随时可以通过浏览器控制台修改页面的前端内容。又或者遇上爬虫程序,直接绕过浏览器直接访问后端。所以后端程序必须设置内容校验,保护后端安全。
基本使用
首先要利用django的form组件为每一个表单都声明一个专属的类,除非表单的需要提交的内容完全相同
from django import forms
class MyForm(forms.Form):
username = forms.CharField(min_length=3,max_length=8)
password = forms.CharField(min_length=6,max_length=20)
email = forms.EmailField()
上面是最基本的类声明例子,每一个类属性(也叫form字段)对应一个输入标签,forms.CharField()中的参数就是该字段(即该输入框的)的条件要求。
渲染标签
首先需要记住form组件只会渲染用户的输入标签(input select radio等),提交按钮还是要用户自己手写的。
下面通过一个例子来讲解form标签的渲染
视图层部分内容:
from django import forms
class RegForm(forms.Form):
name=forms.CharField(max_length=8, label='用户名')
pwd=forms.CharField(max_length=8,label='密码')
email=forms.EmailField()
def register(request):
form_obj=RegForm() #生成空的表单对象
return render(request,'app01/register.html',locals())
模板层部分内容:
<form action="" method="post">
{% csrf_token %}
{% for form_field in form_obj %}
<!-- 循环表单对象,从中获得的表单的字段对象-->
<p>{{ form_field.label }}:{{ form_field }}</p>
<!-- form_field.label表示该字段的label属性 -->
{% endfor %}
<input type="submit" value="注册">
</form>
渲染结果:
总结:
- label属性默认渲染结果是在类中定义的该字段名首字母大写的形式, 也可以自定义直接给字段对象加label属性即可
username = forms.CharField(min_length=3,label='用户名')
- 每个字段对象对应一个输入标签,默认是input标签,input表的name属性为该字段名,id属性为id_加字段名,带有required属性(表现必填)
- 在声明类的时候可以在字段实例化中添加参数,大部分参数会作为input标签的属性渲染出来,例子中的username字段实例化时的参数max_length=8就被渲染在input标签内。
校验数据
校验数据的方法也简单,只需要用声明的表单类接收待校验的数据生成一个表单对象即可,校验的结果可以通过查看生成的表单对象。
注意
待校验的数据需要组成字典的形式
form_obj = RegForm({'username':'jason','password':'123','email':'123'})
校验的流程:
依次拆分字典,以字典的key名等于对应表单类的字段名建立对应关系,然后以表单类中对该字段的声明条件来检查key的值。如果字典的key多于表单类的字段,不影响校验结果。
form_obj.is_valid() #获取校验结果
只要有字典中有一个键值对不合法,则校验结果为False,全部合法则为True
form_obj.cleaned_data #即使form_obj.is_valid()结果为False,字典中合法的数据仍能通过此方法可以找到
form_obj.errors #查看不符合条件的key以及原因
在pycharm中的Python console下测试:
from student.views import Myform
form_obj=Myform({'username':'pks','password':'ewq321','email':'ewq'})
form_obj.is_valid()
False
form_obj.cleaned_data
{'username': 'pks'}
form_obj.errors
{'pwd': ['This field is required.'], 'email': ['Enter a valid email address.']}
##注意看不合法的原因是以列表的形式出现
补充
- forms类中所有的字段默认都是必填的
- 校验的数据可以多传但是不能少传
展示不合法的原因
在上面校验数据的部分提到过form_obj.errors方法可以获取不合法的字段以及其不合法的原因,这里补充下表单对象的每个字段也有errors的方法,当该字段不合法时他能获取不合法的原因,如果字段合法errors便为空。
视图层增加对应POST请求
def reg(request):
form_obj=Myform()
if request.method == "POST":
form_obj=Myform(request.POST)
if form_obj.is_valid():
return HttpResponse('注册成功')
return render(request,'student/register.html',locals())
因此对模板稍作修改
<form action="" method="post">
{% csrf_token %}
{% for form_field in form_obj %}
<!-- 循环表单对象,从中获得的表单的字段对象-->
<p>{{ form_field.label }}:{{ form_field }}</p>
<!-- form_field.label表示该字段的label属性 -->
<span>{{ form_field.errors.0 }}</span>
<!-- 特别注意 form_field.errors一定要加0,不然会被渲染成ul形式,因为不合法的原因是以列表的形式-->
{% endfor %}
<input type="submit" value="注册">
</form>
errors获取的不合法的原因也是可以自定义,在你定义表单类的时候,就可以对每个字段设置一个特别的参数error_messages,该参数以字典的形式出现。字典的每个key必须对应字段设置的参数,key对应的值就是用来自定义不合法的原因。
对表单类修改,举例说明:
username =forms.CharField(label='用户名',max_length=8,min_length=3,
error_messages={"required":"不能为空啊,兄弟",
"min_length":"不能小于三位"
}
)
效果展现如下
forms组件当你的数据不合法的情况下 会保存你上次的数据 让你基于之前的结果进行修改
但前提必备的条件是get请求和post请求传给html页面对象变量名表单对象必须一样
钩子函数
钩子函数在forms组件中就类似于第二道关卡,能够让我们在以字段定义的参数为条件校验成功后,再自定义一些校验条件
在forms组件中有两类钩子
- 局部钩子
当你需要给单个字段增加校验规则的时候使用 - 全局钩子
当你需要给多个字段增加校验规则的时候使用
实际案例
-
校验用户名中不能含有666 只是校验username字段 局部钩子
-
校验密码和确认密码是否一致 password confirm两个字段 全局钩子
钩子函数就是在类里面写方法
# 局部钩子
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
表单类字段的其他参数
initial 默认值
required 控制字段是否必填
widget 为字段增加在前段页面渲染用的属性
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})
# 多个属性值的话 直接空格隔开即可
#validtors利用正则校验该字段
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
]
# RegexValidator()中第一个参数为正则表达式,第二个参数用于定义不合法的原因