17 forms组件
一、校验字段功能
forms.CharField
forms.EmailField
class UserForm(forms.Form): name=forms.CharField(min_length=1,max_length=8) email=forms.EmailField()
form对象方法
- is_valid() 校验数据,字段键必须和form字段一样,传入的数据能多,单不能少,校验成功返回True,校验错误返回False
- cleaned_data 存放校验正确的客户端数据
- errors 校验错误的数据,字典形式。校验字段为键,错误信息为列表类型,可能多个错误信息
校验成功和失败的数据,失败信息打印出来貌似不是字典,实际是字典类型
获取错误信息通过get方法即可获取,错误信息为列表,可通过[0]方式获取
二、渲染标签
通过Form对象渲染模板中的input标签。避免input标签name属性和Form属性名称不统一,减少模板中代码量
CharField--->text
EmailField--->email
方式一:
view中实例化UserForm
form=UserForm() return render(request,'reg.html',{"form":form})
模板中html
<form action="" method="post"> <p>用户名:{{ form.name }}</p> <p>密码:{{ form.pwd }}</p> <p>确认密码:{{ form.r_pwd }}</p> <p>邮箱:{{ form.email }}</p> <p>电话:{{ form.tel }}</p> </form>
方式二:
通过for循环创建标签
给Form类添加label属性,用于label标签显示
class UserForm(forms.Form): #默认有个非空规则 name=forms.CharField(min_length=1,max_length=8,label="用户名") pwd=forms.CharField(min_length=6,label="密码") r_pwd=forms.CharField(min_length=6,label="确认密码") email=forms.EmailField(label="邮箱") tel=forms.CharField(label="电话")
模板中通过for创建标签
获取选软input标签值也可以用field.auto_id
<form action="" method="post"> {% csrf_token %} {% for field in form %} <div><label for="{{ field.id_for_label}}">{{ field.label }}:</label>{{ field }}</div> {% endfor %} <input type="submit" value="submit"> </form>
方式三:
html中标签被故障,无法自定义排版。可测试用,项目不建议使用。
三、显示错误信息以及输入重置功能
主要是模板标签渲染方法
手写input标签,被绑定的数据不会被保留下来,因为压根就没渲染
<form action="" method="POST"> {% csrf_token %} <p>用户名:<input type="text" name="name"><span>{{ form.name.errors.0 }}</span></p> <p>密码:<input type="password" name="pwd"><span>{{ form.pwd.errors.0 }}</span></p> <p>确认密码:<input type="password" name="r_pwd"><span>{{ form.r_pwd.errors.0 }}</span></p> <p>邮箱:<input type="text" name="email"><span>{{ form.email.errors.0 }}</span></p> <p>手机:<input type="text" name="tel"><span>{{ form.tel.errors.0 }}</span></p> <input type="submit" value="submit"> </form>
模板渲染input标签,校验成功的数据会保留,但是错误提示信息并非放在自己写的span标签中,可能是其他原因,需查找官方文档
<form action="" method="post"> {% csrf_token %} <p>{{ form.name.label }}:{{ form.name }}<span>{{ form.name.errors.0 }}</span></p> <p>{{ form.pwd.label }}:{{ form.pwd }}<span>{{ form.pwd.errors.0 }}</span></p> <p>{{ form.r_pwd.label }}:{{ form.r_pwd }}<span>{{ form.r_pwd.errors.0 }}</span></p> <p>{{ form.email.label }}:{{ form.email }}<span>{{ form.email.errors.0 }}</span></p> <p>{{ form.tel.label }}:{{ form.tel }}<span>{{ form.tel.errors.0 }}</span></p> <input type="submit" value="submit"> </form>
四、自定义Form组件
修改标签类型
默认都是text,可以渲染其他标签,如password,checkbox,select等
from django.forms import widgets
自定义错误信息
required:为空错误
invalid:格式错误
class UserForm(forms.Form): #默认有个非空规则 name=forms.CharField(min_length=1,max_length=8,label="用户名",error_messages={"required":"该字段不能为空"}) pwd=forms.CharField(min_length=6,label="密码", widget=widgets.PasswordInput) r_pwd=forms.CharField(min_length=6,label="确认密码",widget=widgets.PasswordInput()) email=forms.EmailField(label="邮箱",error_messages={"required":"该字段不能为空",'invalid':'格式错误'}) tel=forms.CharField(label="电话")
自定义class格式
通过widget添加属性
五、组件校验的局部钩子
局部钩子只能获取和校验一个字段
校验数据是否在数据库中已经存在
from django.core.exceptions import ValidationError from app.models import UserInfo class UserForm(forms.Form): #默认有个非空规则 name=forms.CharField(min_length=1,max_length=8,label="用户名",error_messages={"required":"该字段不能为空"}) pwd=forms.CharField(min_length=6,label="密码", widget=widgets.PasswordInput(attrs={"class":"form-control"})) r_pwd=forms.CharField(min_length=6,label="确认密码",widget=widgets.PasswordInput()) email=forms.EmailField(label="邮箱",error_messages={"required":"该字段不能为空",'invalid':'格式错误'}) tel=forms.CharField(label="电话") # 判断数据是否已经在数据库中 def clean_name(self): val=self.cleaned_data.get("name") ret=UserInfo.objects.filter(name=val) if not ret: return val else: raise ValidationError("该用户已注册")
钩子源码解析
自定义钩子验证数据
class UserForm(forms.Form): #默认有个非空规则 name=forms.CharField(min_length=1,max_length=8,label="用户名",error_messages={"required":"该字段不能为空"}) pwd=forms.CharField(min_length=6,label="密码", widget=widgets.PasswordInput(attrs={"class":"form-control"})) r_pwd=forms.CharField(min_length=6,label="确认密码",widget=widgets.PasswordInput()) email=forms.EmailField(label="邮箱",error_messages={"required":"该字段不能为空",'invalid':'格式错误'}) tel=forms.CharField(label="电话") # 通过钩子验证数据,判断数据是否已经在数据库中 #钩子名称一定是clean_格式 def clean_name(self): val=self.cleaned_data.get("name") ret=UserInfo.objects.filter(name=val) if not ret: return val else: #数据验证错误一定返回ValidationError raise ValidationError("该用户已注册!") def clean_tel(self): val=self.cleaned_data.get('tel')#取得tel号码 if len(val)==11: return val else: raise ValidationError('手机号码长度不对!')
六、全局钩子
如密码与确认密码的对比
父类中的clean方法啥都没做,这里是留给用户的接口。
全局钩子和局部钩子区别:
- 全局钩子可以获取多个数据
- 全局钩子校验不正确时,数据任然在cleaned_data中。局部钩子校验失败的则没有在cleaned_data中
在form类中自定期clean方法
class UserForm(forms.Form): #默认有个非空规则 name=forms.CharField(min_length=1,max_length=8,label="用户名",error_messages={"required":"该字段不能为空"}) pwd=forms.CharField(min_length=6,label="密码", widget=widgets.PasswordInput(attrs={"class":"form-control"})) r_pwd=forms.CharField(min_length=6,label="确认密码",widget=widgets.PasswordInput()) email=forms.EmailField(label="邮箱",error_messages={"required":"该字段不能为空",'invalid':'格式错误'}) tel=forms.CharField(label="电话") # 通过钩子验证数据,判断数据是否已经在数据库中 #钩子名称一定是clean_格式 def clean_name(self): val=self.cleaned_data.get("name") ret=UserInfo.objects.filter(name=val) if not ret: return val else: #数据验证错误一定返回ValidationError raise ValidationError("该用户已注册!") def clean_tel(self): val=self.cleaned_data.get('tel')#取得tel号码 if len(val)==11: return val else: raise ValidationError('手机号码长度不对!') def clean(self): pwd=self.cleaned_data.get('pwd') r_pwd=self.cleaned_data.get('r_pwd') if pwd == r_pwd: return self.cleaned_data else: raise ValidationError("两次密码不一致")
全局错误在form.errors.get("__all__")中
views中获取
def reg(request): if request.method == "POST": # userform=UserForm({'name':'ya','email':'123.com','pwd':'123','r_pwd':'123'}) userform=UserForm(request.POST)#绑定数据的表单 if userform.is_valid():#校验所有字段 #如果所有字段校验正确,正确的数据会放在cleaned_data中 data=userform.cleaned_data pass else: post_data=userform.cleaned_data#校验成功的数据 err_data=userform.errors#校验错误的数据,字典形式。校验字段为键,错误信息为列表类型,可能多个错误信息 print(post_data) print(err_data) print(err_data.get("__all__")[0]) return render(request, 'reg.html',{"form":userform}) else: form=UserForm()#未绑定数据的表单 return render(request,'reg.html',{"form":form})
在views中将全局errors赋值给errors
errors=err_data.get("__all__") return render(request, 'reg.html',{"form":userform,'errors':errors})
在模板中通过.0获取即可。这里获取第一个放在模板中获取,避免没有全局错误的时候在views中报错
<form action="" method="post"> {% csrf_token %} <p>{{ form.name.label }}:{{ form.name }}<span>{{ form.name.errors.0 }}</span></p> <p>{{ form.pwd.label }}:{{ form.pwd }}<span>{{ form.pwd.errors.0 }}</span></p> <p>{{ form.r_pwd.label }}:{{ form.r_pwd }}<span>{{ form.r_pwd.errors.0 }}</span><span>{{ errors.0 }}</span></p> <p>{{ form.email.label }}:{{ form.email }}<span>{{ form.email.errors.0 }}</span></p> <p>{{ form.tel.label }}:{{ form.tel }}<span>{{ form.tel.errors.0 }}</span></p> <input type="submit" value="submit"> </form>
避免第一步密码不满足长度为4的要求,而提示两次密码不一致的问题,在全局钩子中多加一步验证即可
七、ModelForm需找其他资料学习
后面的项目实战CRM有使用