form组件
forms组件引入
- 需求
写一个注册功能
获取用户名和密码 利用form表单提交数据
在后端判断用户名和密码是否符合一定的条件
用户名中不能含有金瓶
密码不能少于三位
将不符合的提示信息在输入框后面展示
- 代码实现
# 后端代码
def ab_form(request):
back_dic = {'username':'','password':''}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if '金瓶' in username:
back_dic['username'] = '不符合规范'
if len(password) < 3:
back_dic['password'] = '太短了'
return render(request,'ab_form.html',locals())
# 前端代码
<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="text" name="password">
<span style="color: red">{{ back_dic.password }}</span>
</p>
<input type="submit" class="btn btn-info">
</form>
</body>
- 分析
1.手动书写前端获取用户数据的html代码 渲染html代码
2.后端对用户数据进行校验 校验数据
3.对不符合要求的数据进行前端提示 展示提示信息
forms组件基本使用
介绍
在上面forms组件引入中,自己写了代码校验用户输入是否符合某一个标准,页面也是手动渲染的,对不符合要求的数据的提示也是自己来判断的。
forms组件的作用就是可以不需要手动实现以上三个需求!!!
基本使用
from django import forms
class MyForm(forms.Form):
# username字符串类型,最小3位,最大8位
username = forms.CharField(max_length=8,min_length=3)
# password,字符串类型,最小3位,最大8位
password = forms.CharField(max_length=8,min_length=3)
# email字段必须符合邮箱格式
email = forms.EmailField()
校验数据(是否符合参数的设定)
- 测试环境准备
- 方式一:通过test.py文件进行测试
- 方式二:pycharm中准备好的测试环境,Python console
- 使用方式二进行测试
# 1 首先导入需要测试的文件
from app01 import views
# 2 将校验数据组织成字典的形式传入自定义的类进行校验
form_obj = views.MyForm({'username':'chloe','password':'1026','emali':'123'})
# 3 判断数据是否合法:注意该方法只有在所有的数据全部合法的情况下才会返回True
form_obj.is_valid() # False
# 4 查看所有校验通过的数据
form_obj.cleaned_data
{'username':'chloe','password':'1026'}
# 5 查看所有不符合校验规则的字段以及不符合的原因
form_obj.errors()
{
'email': ['Enter a valid email address.']
},这里结果的值是一个列表,原因是校验条件可能有多个都不符合
# 6如果校验数据中出现了类中没有的字段,forms组件只会校验存在的字段,不存在的字段传了直接忽略
form_obj = views.MyForm({'username':'chloe','password':'1026','emali':'123@qqcom','hobby':'read'})
form_obj.is_valid() # True
# 7 默认情况下,类里面所有的字段都必须传值,也就意味着校验数据的时候,默认情况下数据可以多传但是不能少传
form_obj = views.MyForm({'username':'jason','password':'123'})
form_obj.is_valid()
False
渲染标签
form组件会自动帮忙渲染获取用户输入的标签(input select radio checkbox),但是不能自动渲染提交按钮
- 后端代码
def index(request):
# 1 先产生一个空对象
form_obj = MyForm()
if request.method == 'POST':
# 3 获取用户数据进行校验,如果一条一条的获取用户数据太过繁琐,而且校验数据需要字典格式,而request.POST获取到的数据格式就是queryset——dict对象
form_obj = MyForm(request.POST)
# 4 如果数据合法应该操作数据库,这里先简写
if form_obj.is_valid():
return HttpResponse('OK')
# 5 如果数据不合法,就需要将错误信息展示到前端
# 问题:如何展示到前端呢?因为form校验产生的错误信息就是字典格式,到前端就是自定义对象,所以可以通过前端点点点的方式
# 2 直接将空对象传递给html页面
return render(request,'index.html',locals())
- 前端代码
<body>
<form action="" method="post" novalidate>
<p>第一种渲染方式:代码数学极少,封装程度太高,扩展性不好</p>
{# {{ form_obj.as_p }}#}
{# {{ form_obj.as_ul }}#}
{# {{ form_obj.as_table }}#}
<p>第二种渲染方式:扩展性性很强,但是需要书写的代码太多</p>
{# {{ form_obj.username.label }}{{ form_obj.username }}#}
{# {{ form_obj.password.label }}{{ form_obj.password }}#}
{# {{ form_obj.email.label }}{{ form_obj.email }}#}
<p>第三种渲染方式:推荐使用,代码精简,并且扩展性也很高</p>
{% for form in form_obj %}
<p>
{{ form.label }}{{ form }}
// form.errors.0的意思是只展示第一条错误提示,否则forms组件会将错误信息展示成无序列表的形式
<span style="color: red">{{ form.errors.0 }}</span>
</p>
{% endfor %}
<input type="submit" class="btn btn-info">
</form>
</form>
</body>
HOOK钩子函数
简介
在特定的节点自动触发完成相应操作,写在类中
钩子函数在forms组件中就类似与第二道关卡,能够自定义校验规则
在forms组件中有两类钩子
- 局部钩子:当你需要给单个字段增加校验规则的时候可以使用
- 全局钩子:当你需要给多个字段增加校验规则的时候可以使用
案例
- 校验用户名中不能含有666 只是校验username字段 局部钩子
- 校验密码和确认密码是否一致 password confirm两个字段 全局钩子
# 钩子函数
# 局部钩子
def clean_username(self):
# 获取到用户名
username = self.cleaned_data.get('username')
if '666' in username:
# 前端展示错误信息
self.add_error(field='username',error='666不行')
# 将钩子函数钩取出来的数据再放回去
return username
# 全局钩子
def clean(self):
password = self.cleaned_data.get('password')
cof_password = self.cleaned_data.get('confirm_password')
if not cof_password == password:
self.add_error('confirm_password','两次密码不一致')
return self.cleaned_data
forms组件其他参数及补充知识点
参数补充
- lable字段名
- error_messages 自定义报错信息
username = forms.CharField(min_length=3,max_length=8,label='用户名',error_messages={
'min_length':'最少三位',
'max_length':'最多八位',
'required':'不能为空',
})
-
initial 默认值
-
required 控制字段是否必填
字段的样式修改
forms组件默认没有使用bootstrap的样式,如何使用呢?针对不同类型的input框(text password date等)如何修改呢
- 针对input标签的属性值
widget=forms.widgets.PasswordInput(attrs={'class':'form-control c1 c2'})
# 多个属性值的话 直接空格隔开即可
- 第一道关卡里面还支持正则校验
validators=[
RegexValidator(r'^[0-9]+$', '请输入数字'),
RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
]
- input框其他类型渲染
# 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()
)