手动实现一个注册功能用户名不能含有'haha',密码不能小于3位数
<!--前端-->
<form action="" method="post">
<p>username:<input type="text" name="username">
<span>{{ errors.username }}</span></p> <!--用于展示错误提示-->
<p>password:<input type="text" name="password">
<span>{{ errors.password }}</span></p>
<input type="submit">
</form>
# 后端
def login(request):
# 定义一个报错信息字典,用于前端span标签错误提示
errors = {'username':'', 'password':''}
if request.method == 'POST':
# 获取到用户名合密码
username = request.POST.get('username')
password = request.POST.get('password')
# 判断用户名和密码规则
if 'haha' in username:
errors['username'] = '用户名不规范'
if len(password) < 3:
errors['password'] = '密码不能小于位'
return render(request, 'login.html', locals())
# 整个过程共三步: 1.前端页面搭建 >>> 渲染页面 2.数据传输到后端校验 >>> 校验数据 3.战术错误信息 >>> 展示信息
一.什么用forms组件
Django form组件能直接完成上面的三步操作:1.渲染前端页面2.校验数据是否合法3.展示错误信息
二.如何使用forms组件
<1> 写一个继承了forms.Form的类
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(max_length=8,min_length=3) # 用户名最长八位最短三位
password = forms.CharField(max_length=8,min_length=5) # 密码最长八位最短五位
email = forms.EmailField() # email必须是邮箱格式
<2>基本使用
# 在Python Console校验
1.将需要校验的数据,以字典的方式传递给自定义的类,实例化产生对象
form_obj = views.LoginForm({'username':'xionger','password':'123','email':'123'})
2.查看数据是否全部合法
form_obj.is_valid() >>> False # 只有所有的数据都符合要求 才会是True
3.查看错误的字段及原因
form_obj.errors # 返回的是字典{字段名:[错误信息],...}
{
'password': ['Ensure this value has at least 5 characters (it has 3).'],
'email': ['Enter a valid email address.']
}
4.查看校验合格的字段数据
form_obj.cleaned_data # 返回的是字典{字段名:值,...}
{'username': 'xionger'}

注意:
1.自定义类中所有的字段默认都是必须要传值的
2.可以额外传入类中没有定义的字段名,forms组件不会去校验,也就意味着多传一点关系没有
form_obj = views.LoginForm({'username':'xionger','password':'123456','email':'123@qq.com'})
form_obj.is_valid()
True
form_obj = views.LoginForm({'username':'xionger','password':'123456'})
form_obj.is_valid()
False # 少一个字段
form_obj = views.LoginForm({'username':'xionger','password':'123456','email':'123@qq.com','hobby':'read'})
form_obj.is_valid()
True # 多出的字段不进行校验
<3>渲染页面
三种方式
<p>第一种渲染页面的方式(封装程度太高 一般只用于本地测试 通常不适用)</p>
{{ from_obj }}
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
<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>
<p>第三种渲染页面的方式(推荐)</p>
{% for foo in form_obj %}
<p>{{ foo.label }}{{ foo }}</p>
{% endfor %}
<!--
form_obj 是LoginForm类的对象
form_obj.username 是 字段forms.CharField类的对象
form_obj.username.label 是对象 form_obj.username 的属性
foo == form_obj.username
foo.label == form_obj.username.label
-->

注意:
1.forms组件在帮你渲染页面的时候,只会渲染获取用户输入的标签,提交按钮需要你手动添加2.input框的label注释,不指定的情况下,默认用的类中字段的首字母大写
<4>展示错误信息
<!--前端-->
{% for foo in form_obj %}
<p>{{ foo.label }}{{ foo }}
<span>{{ foo.errors.0 }}</span> <!--foo.errors是错误的字段-->
</p>
{% endfor %}
# 后端
def reg(request):
# 1 现生成一个空的自定义类的对象
form_obj = LoginForm()
# 2 将该对象传递给前端页面
if request.method == 'POST':
# 3 获取前端post请求提交过来的数据
# print(request.POST) # 由于request.POST其实也是一个字典,所以可以直接传给LoginForm
form_obj = LoginForm(request.POST)
# 4 校验数据 让forms组件帮你去校验
if form_obj.is_valid():
# 5 如果数据全部通过 应该写入数据库
pass
# 6 如果不通过 前端展示错误信息
return render(request,'reg.html',locals())
<5>钩子函数(HOOK)
forms组件暴露给用户可以自定义的校验规则
用法:在自定义的form类中书写方法即可
(1)局部钩子 clean_字段名 :针对某一个字段做额外的校验
def clean_username(self):
# 需要额外校验的字段
username = self.cleaned_data.get('username')
if '666' in username:
# 添加提示的错误信息
self.add_error('username', '用户名不能有666')
# 将字段返回
return username
(2)全局钩子 clean : 针对多个字段做额外的校验
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','两次密码不一致')
# 与局部钩子不同,这里需要将 cleaned_data 返回
return self.cleaned_data
补充:
1.校验数据的时候可以前后端都校验,做一个双重的校验 但是前端的校验可有可无,而后端的校验则必须要有,因为前端的校验可以通过爬虫直接避开 前端取消浏览器校验功能: <!--form标签指定novalidate属性即可--> <form action="" method='post' novalidate></form>
2.forms组件其他字段及操作方式:
required 是否必填
label 注释信息
error_messages 报错信息
initial 默认值
widget 控制标签属性和样式
widget=widgets.PasswordInput(attrs={'class':'form-control c1 c2'}) # 改成密文,添加样式
3.其他字段了解知识点(知道有这些对象 需要用到的时候 能够知道去哪找)
# 单选的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()
)
# 正则
phone = forms.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)

