forms组件
例如我们写一个注册功能,要求是:
用户输入的用户名中 不能包含666
如果包含了 就提示用户 输入的内容不符合社会主义核心价值观
用户输入的密码 不能小于三位
如果密码少于三位 提示用户 密码太短了
这就需要搭建前端页面,对前端用户提交的数据进行校验,将错误信息展示到前端页面给用户看
要注意的是:校验数据通常是前后端都有校验
但是前端校验可有可无 哪怕再牛逼
后端也必须要有校验 反正一句话 前端可有不校验 后端必须校验!!!
1.搭建前端页面 >>> 渲染页面
2.获取前端用户提交的数据校验 >>> 校验数据
3.对数据的校验的结果 展示到前端页面给用户查看 >>> 展示错误信息
forms组件能够自动帮你完成三件事:
- 渲染页面
- 校验数据
- 展示信息
forms组件基本用法
1、首先要先写一个类
from django import forms
class MyRegForm(forms.Form):
username = forms.CharField(min_length=3,max_length=8)
password = forms.CharField(min_length=3,max_length=8)
email = forms.EmailField()
2、如何校验数据
在pycharm下面的Python Console窗口中进行校验测试,会自动搭建测试环境
测试代码:
from app01 import views
# 1.给自定义的类传一个字典
obj = views.MyRegForm({'username':'jason','password':'12','email':'123'})
# 2.判断数据是否全部合法
obj.is_valid() # 只有数据全部符合要求才会是True
Out[4]: False
# 3.查看符合校验规则的数据
obj.cleaned_data
Out[5]: {'username': 'jason'}
# 4.查看不符合条件的数据以及不符合的原因是什么
obj.errors
Out[6]:
{
'password': ['Ensure this value has at least 3 characters (it has 2).'],
'email': ['Enter a valid email address.']
}
# 5.校验数据的时候 默认情况下类里面所有的字段都必须传值
obj = views.MyRegForm({'username':'jason','password':'123'})
obj.is_valid()
Out[12]: False
obj.errors
Out[13]: {'email': ['This field is required.']} # 没有给表中的email字段传值,就无法通过校验
# 6.默认情况下可以多传 但是绝对不能少传
obj = views.MyRegForm({'username':'jason','password':'1233','email':'123@qq.com','xxx':'ooo'})
obj.is_valid()
Out[15]: True
渲染页面
注意事项:
1.forms组件在帮你渲染页面的时候 只会渲染获取用户输入(输入,选择,下拉框...)的标签 提交按钮需要你手动添加
2.input框的label注释 不指定的情况下 默认用的类中字段的首字母大写
三种渲染前端页面的方式
后端
from django import forms
class MyRegForm(forms.Form):
username = forms.CharField(min_length=3,max_length=8,label='用户名')
password = forms.CharField(min_length=3,max_length=8,label='密码')
email = forms.EmailField(label='邮箱')
def formmm(request):
# 1.生成一个空的对象
form_obj = MyRegForm()
if request.method == 'POST':
# 2.获取用户提交的数据
# print(request.POST) # request.POST 其实也可以看成是一个字典
# 3.借助于form组件帮助我们校验
form_obj = MyRegForm(request.POST) # 由于request.POST其实就是一个大字典 所以直接当做参数传入即可 # 注意:这个form_obj对象名必须跟上面的form_obj对象名一致
# 4.判断用户输入的数据是否符合校验规则
if form_obj.is_valid():
return HttpResponse('你上传的数据没有问题')
return render(request,'formmm.html',locals())
第一种渲染页面的方式(封装程度太高,标签样式及参数不方便调整,可扩展性差,一般只用于本地测试 不推荐使用)
<p>
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
</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>
{% for foo in form_obj %}
<P>{{ foo.label }}{{ foo }}</P>
{% endfor %}
</p>
想要input框前的名字是中文,在后端的字段中直接加参数label='用户名'
eg :
# views.py
from django import forms
class MyRegForm(forms.Form):
username = forms.CharField(min_length=3,max_length=8,label='用户名')
password = forms.CharField(min_length=3,max_length=8,label='密码')
email = forms.EmailField(label='邮箱')
如何展示错误信息
取消前端校验功能
校验数据的时候可以前后端都校验 做一个双重的校验,但是前端的校验可有可无,而后端的校验则必须要有,因为前端的校验可以通过爬虫直接避开。
前端取消浏览器校验功能:form标签添加novalidate属性即可:<form action="" method='post' novalidate></form>
展示错误信息
展示错误信息:用后端传过来的对象.errors.0
form action="" method="post" novalidate>
{% for foo in form_obj %}
<p>
{{ foo.label }}:{{ foo }} <!--渲染前端页面-->
<span style="color: red">{{ foo.errors.0 }}</span> <!--展示错误信息显示在input框的后面-->
</p>
{% endfor %}
<input type="submit">
</form>
上述的方法展示出来的错误信息时英文,那怎么把它变成中文显示呢,来看以下代码:
from django import forms
class MyRegForm(forms.Form):
username = forms.CharField(min_length=3,max_length=8,label='用户名',
# 指定error_messages参数来把错误信息用中文展示出来
error_messages={
'min_length':'用户名最短三位',
'max_length':'用户名最长八位',
'required':'用户名不能为空'
},initial='我是初始值' # 这个参数是给input框设置初始值
)
password = forms.CharField(min_length=3,max_length=8,label='密码',
error_messages={
'min_length':'密码最短三位',
'max_length':'密码最长八位',
'required':'密码不能为空'
})
email = forms.EmailField(label='邮箱',error_messages={
'required':'邮箱不能为空',
'invalid':'邮箱格式不正确'
},required=False) # 把required参数指定为False,表示这个字段的参数可以不传,如果传了的话也依然还是会校验的。
forms组件钩子函数
当你需要对某一个字段数据进行额外的一系列校验,可以考虑使用钩子函数
钩子函数是forms组件暴露给用户,可以自定义的校验规则
必须通过字段本身之前的校验规则,才会进行钩子函数的校验。
用法:在自定义的form类中书写方法即可
局部钩子
针对单个字段的,使用局部钩子
# 局部钩子(针对某一个字段做额外的校验) 校验用户名中不能包含666 一旦包含 提示
def clean_username(self):
username = self.cleaned_data.get('username')
if '666' in username:
# 给username字段下面提示错误信息
self.add_error('username','光喊666是不行的 你得自己上')
return username
全局钩子
针对多个字段的校验,使用全局钩子,eg:校验两次密码是否一致
def clean(self):
password = self.cleaned_data.get('password')
confirm_password = self.cleaned_data.get('confirm_password')
if not password == confirm_password:
self.add_error('confirm_password','两次密码不一致')
return self.cleaned_data
forms组件其他字段及操作方式
required 是否必填
label 注释信息
error_messages 报错信息
initial 默认初始值
widget 控制标签属性和样式
如何改变input框的type属性值
需要给字段指定widget参数来控制标签属性
widget= widgets.TextInput()
widget=widgets.PasswordInput()
如何让forms组件渲染出来的input框有form-control类属性
widget= widgets.TextInput(attrs={'class':'form-control others'}) # 如果有多个类属性 空格隔开
widget=widgets.PasswordInput(attrs={'class':'form-control others'})
eg:
from django import forms
from django.forms import widgets # 当你forms点不出来的时候 你可以手动导入一下
class MyRegForm(forms.Form):
username = forms.CharField(min_length=3,max_length=8,label='用户名',
error_messages={
'min_length':'用户名最短三位',
'max_length':'用户名最长八位',
'required':'用户名不能为空'
},initial='我是初始值',required=False,
widget= widgets.TextInput(attrs={'class':'form-control others'})
)
password = forms.CharField(min_length=3,max_length=8,label='密码',error_messages={
'min_length':'密码最短三位',
'max_length':'密码最长八位',
'required':'密码不能为空'
},widget=widgets.PasswordInput())
email = forms.EmailField(label='邮箱',error_messages={
'required':'邮箱不能为空',
'invalid':'邮箱格式不正确'
},required=False,widget=widgets.EmailInput(attrs={'class':'form-control'}))
其他字段了解知识点(知道有这些对象 需要用到的时候 能够知道去哪找)
# 单选的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()
)
# 多选的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()
)
每个字段,还支持正则校验
需要导入RegexValidator模块
eg:
from django import forms
from django.forms import Form
from django.core.validators import RegexValidator
class MyForm(Form):
phone = forms.CharField(label='手机号',
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)