13、form组件
一、form前戏
这里抛出一个问题,我们写一个注册功能的时候,获取用户数据和密码,利用form表单来提交数据。
然后我们在后端需要判断用户名和密码是否符合一定的条件,比如说用户提交的用户名不能包含一些敏感词汇,否则不符合社会主义核心价值观,密码不能少于三位数,否则提示用户密码太短。首先我们直接纯手写一个吧,先把HTML页面搭出来
<body>
<form action="" method="post">
<p>
<label>
用户
<input type="text" name="username">
<span style="color: red">{{ back_dic.username }}</span>
</label>
</p>
<p>
<label>
密码
<input type="text" name="password">
<span style="color: red">{{ back_dic.password }}</span>
</label>
</p>
<input type="submit" class="btn btn-info">
</form>
</body>
</html>
后端视图层代码如下
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())
我们上面这段自己写的代码干了以下几件事
1.搭建前端HTML页面(渲染页面)
2.后端获取前端数据进行校验(校验数据)
3.对不符合要求的数据进行前端页面的展示 (展示错误信息)
二、form组件书写
现在有一个东西可以帮助我们完成这三个功能,那就是form组件
我们先要在视图层导入以下代码
from django import forms
class MyForm(forms.Form):
# username字段是字符串类型,最小3位,最大8位
username = forms.CharField(min_length=3,max_length=8)
# password字段是字符串类型,最小3位,最大8位
password = forms.CharField(min_length=3,max_length=8)
# email字段必须符合邮箱格式(@xx.com)
email = forms.EmailField()
三、form组件校验数据
如何校验数据,可以在Python控制台进行测试
from app01 import views
# 1.给自定义的类传一个字典
obj1 = views.MyForm({'username':'poco','password':'1234','email':'123'})
# 2.判断数据是否全部合法
obj1.is_valid() # 只有数据全部符合要求才会是True,很显然,结果肯定是false,邮箱格式不对
# 3.查看符合校验规则的数据
obj1.cleaned_data
# 结果:{'username': 'poco', 'password': '1234'}
# 4.查看不符合条件的数据以及不符合的原因是什么
obj1.errors
# 结果:{'email': ['Enter a valid email address.']}
# 5.校验数据的时候,默认情况下类里面所有的字段都必须传值
obj2 = views.MyForm({'username':'wendy','password':'123'})
obj2.is_valid()
# 结果:False
obj2.errors
# 结果:{'email': ['This field is required.']}
# 6.默认情况下可以多传,但是绝对不能少传
obj3 = views.MyForm({'username':'jason','password':'1233','email':'123@qq.com','age':'22'})
obj3.is_valid()
# 结果: True
四、form渲染HTML页面
首先后端代码
def ab_form(request):
# 1.先产生一个空对象
form_obj = MyForm()
# 2.直接将该空对象传递给HTML页面
return render(request, 'ab_form.html', locals())
1、第一种渲染方式
前端代码,这种渲染方式代码书写少,但封装程度高,不便于后续拓展,一般只用于本地测试
<form action="" method="post">
<p>第一种渲染方式</p>
{{ form_obj.as_p }}
{# {{ form_obj.as_ul }}#}
{# {{ form_obj.as_table }}#}
</form>

我们前端并没有写input输入框的标签,但页面已经有了。这些 输入框的名字都是取决于你后端书写的那个类。
2、第二种渲染方式
通过对象.username的方式渲染输入框,又可以通过.label又可以拿到名字。这个名字还可以通过后端的类代码来自定义名字
class MyForm(forms.Form): username = forms.CharField(min_length=3, max_length=8,label='用户名')这种方式扩展性高,但是需要手写大量代码,所以也不推荐。
<form action="" method="post">
<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>
</form>
我们知道用.xxx的方式其实
3、第三章渲染方式(推荐)
代码书写简单,并且扩展性高
<form action="" method="post"> <p>第三种渲染方式</p> {% for form in form_obj %} <p>{{ form.label }}{{ form }}</p>】 {% endfor %}</form>
五、form展示提示信息
首先我们要把前端对我们做的校验取消掉,也就是浏览器,他会自动帮你做校验,如果你设置了最长的用户名为8位,这时候你是不能输入超越8位的字符的,会直接卡在那里,所以我们要取消前端帮我们做的校验,只需要在form表单中添加一个参数novalidate就可以了。
<form action="" method="post" novalidate> {% for form in form_obj %} <p> {{ form.label }}{{ form }} <span style="color: red">{{ form.errors.0 }}</span> </p> {% endfor %} <input type="submit"></form>
后端
def ab_form(request): # 1.先产生一个空对象 form_obj = MyForm() if request.method == 'POST': # 获取用户数据并校验 form_obj = MyForm(request.POST) # 判断数据是否违规 if form_obj.is_valid(): # 不违规,存储数据 pass else: # 违规,展示给前端 pass # 2.直接将该空对象传递给HTML页面 return render(request, 'ab_form.html', locals())# 这里错误信息显示的都是英文,如何变成中文。找到当初写form组件的那个类,写以下几个参数class MyForm(forms.Form): # username字段是字符串类型,最小3位,最大8位 username = forms.CharField(min_length=3, max_length=8, label='用户名', error_messages={ 'min_length': '用户名最少3位', 'max_length': '用户名至少8位', 'required': '密码不能为空'}) # password字段是字符串类型,最小3位,最大8位 password = forms.CharField(min_length=3, max_length=8) # email字段必须符合邮箱格式(@xx.com) email = forms.EmailField()
六、forms组件钩子函数
钩子函数(HOOK),是一种在特定的节点自动触发完成响应的操作,钩子函数就是第二道关卡,能够让我们自定义校验规则
在forms组件中有两类钩子
1.局部钩子:给单个字段增加校验规则
2.全局钩子:给多个字段增加校验规则
# 针对单个字段的 使用局部钩子 eg:用户名不能有xxx
def clean_username(self):
# 对象里有cleaned_data这个属性,拿到了里面的username来看一下
username = self.cleaned_data.get('username')
if 'xxx' in username:
# 提示前端展示错误信息
self.add_error('username','xxx是敏感词汇,不能使用!')
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组件其他参数以及补充知识点
label 字段名
error_messages 自定义报错信息
initial 默认值
required 控制字段是否必填
# 如何改变inpu框的type属性值
# 如何改变input框的type属性值
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'})

浙公网安备 33010602011771号