1简介
# 应用场景
应用于前端向后端提交数据,后端需要对数据进行校验并向前端返回结果的情况,如注册。
# 主要功能
1.生成页面可用的HTML标签
2.对用户提交的数据进行校验
3.保留上次输入内容
# 为什么不在前端校验
前端发送的数据不安全,可以认为修改,故只在前端校验是没意义的。通常前后端同时校验,双重保险。
2基本语法
"""form在使用前要先新建类"""
例:
from django import forms
# 自定义类,并声明数据限制
class RegForm(forms.Form):
name = forms.CharField(max_length=8, min_length=3, required=True, # 常规限制条件
label="用户名", # 设置提示信息,默认字段名首字母大写
widget=forms.widgets.TextInput(attrs={"class": "form-control"}), # 设置表单类型和样式
initial='懒逼', # 初始值
error_messages={ # 添加报错信息
"max_length": "不能超过8个字符",
"min_length": "不能少于3个字符",
"required": "不能为空",
#'invalid':'邮箱格式错误'(邮箱格式专用)
}
)
pwd = forms.CharField(min_length=3,max_length=8)
email = forms.EmailField(label='') # 要满足邮箱格式XXX@XX.com
# 注释:
1.上述代码书写位置:通常是在应用文件夹下单独建立一个.py文件,写在里面
2.每一种字段都默认有label属性,是该字段的提示信息,不写默认是字段名(且首字母大写)
3.字段的匹配条件还可以写正则
4.可以通过error_message属性自定义错误提示信息
2.2后端数据校验
"""""""""""""""""""""""""""方案1"""""""""""""""""""""""""""
1.要先从前端获得数据
2.实例化
form_obj=RegForm('username':'json','password':'123','email':'123') # 只校验类中定义的字段,多传直接忽略,少传默认就是校验失败
3.判断数据是否符合要求
form_obj.is_valid() # 判断是否所有数据都符合要求,返回True/False
form_obj.cleaned_data # 返回符合要求的数据
form_obj.errors # 返回不符合要求的数据和不符合的原因
""""""""""""""""""""""方案2(推荐)""""""""""""""""""""""
1.实例化form对象的时候,把post提交过来的数据直接传进去
form_obj = RegForm(request.POST)
2.调用form_obj方法校验数据
form_obj.is_valid()
#例子:
def my_form(request):
form_obj = RegForm() # 产生空对象,用于前端第一次渲染input标签
if request.method == "POST":
form_obj = RegForm(request.POST) # 产生新的对象替换先前的对象,使得form_obj中拥有数据,这是保证form组件能记录先前数据的关键
if form_obj.is_valid():
return HttpResponse('合法')
return render(request,'my_form.html',lcals())
# 注释:
1.应用form组件时前端会自动进行校验,在form表单中加入novalidate标签关闭此功能
2.后端2次实例化的对象名要一致,不然无法保存上一次书写的数据
2.3前端渲染标签
# 标签渲染之渲染input框和提示信息,不会渲染提交按钮,按钮要手动渲染
"""方案1"""
# 自动渲染input框和提示信息,
# 代码书写少,封装程度高,扩展性差
{{ form_obj.as_p }} # 渲染在p标签中
{{ form_obj.as_ul }} # 渲染在ul标签中
{{ form_obj.as_table }} # 渲染在一行
"""方案2"""
# 手动渲染input框和提示信息,
# 代码书写多,扩展性好
<p>{{ form_obj.username.label}}:{{ form_obj.username}}</p>
# form_obj.username.label 渲染提示信息
# form_obj.username 渲染input框
"""方案3(推荐)"""
# 在手动渲染的基础上加上for循环,使得无论有多少字段,都3行代码搞定
{% for form in form_obj %}
<p>{{ form.label}}:{{ form}}</p> # form相当于form_obj.username
{% endfor%}
2.4前端展示错误信息
"""""""""""""""""""""""""""""""""前端"""""""""""""""""""""""""""""""""
例子:
{% for form in form_obj %}
<p>
{{ form.label}}:{{ form}} # form相当于form_obj.username
<span style='color:red'>{{ form.errors.0 }}</span> # form.errors就是报错信息,这是一个列表,通常我们只取其中的第一条原因用于渲染
</p>
{% endfor%}
"""
在特定的节点自动触发,完成响应操作。
本质是对form组件进行2次校验,当某一字段form组件校验成功时,就会走钩子函数再进行校验。
"""
分类:
1.局部钩子
只给单一字段添加校验规则
2.全局钩子
给多个字段添加校验规则
语法:
# 钩子函数定义在form类中,作为类方法存在,但会自动调用。
# 定义局部钩子,用来校验username字段,使其不能有666
def clean_username(self):
value = self.cleaned_data.get("username") # 获取当前字段值
if "666" in value:
self.add_error('username', '不要加666') # 指定报错提示信息
return value # 返回钩子
# 定义全局的钩子,用来校验密码和确认密码字段是否相同
def clean(self):
password_value = self.cleaned_data.get('password')
re_password_value = self.cleaned_data.get('re_password')
if not password_value == re_password_value:
self.add_error('re_password', '两次密码不一致')
return self.cleaned_data
4字段的属性
label # 提示信息
error_message # 自定义报错信息
initial # 默认值
required # 控制字段是否必需要填写(能否为空),true/false
如何修改标签样式和属性?
# widget修改标签样式
# 括号中写attrs={}填写标签属性,以字典的形式传参,多个属性值用空格隔开
widget=forms.widgets.TextInput(attrs={'class':'form-control',}) # 文本框
widget=forms.widgets.PasswordInput() # 密文输入框
widget=forms.widgets.EmailInput()
自定义正则校验规则
validators=[
RegexValidator(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$','错误提示信息'),
RegexValidator(), # 可以写多条
]
5补充其它渲染标签样式
# radio
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
initial=3,
widget=forms.widgets.RadioSelect()
# 单选checkbox
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
# 多选checkbox
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
# 单选Select
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
# 多选Select
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()