1. 用途
- 数据校验
- 标签渲染
- 渲染错误信息
2. 用法(已注册验证为例)
-
先建一个user表迁移数据库就不说了, 字段为name,pwd,email
-
写一个类继承Form , 这个类用来设置校验规则的
from django import forms from django.forms import widgets from django.core.exceptions import ValidationError class MyForm(forms.Form): name = forms.CharField( max_length=8, min_length=3, label='用户名', error_messages={'max_length': '最大长度为8', 'min_length': '最小长度为3', 'invalid': '不符合邮箱格式', 'required': '这个必须填'}, widget=widgets.TextInput( attrs={'class': 'form-control', 'placeholder': '请输入用户名', 'id': 'name'} ) ) pwd = forms.CharField( max_length=8, min_length=3, label='密码', error_messages={'max_length': '最大长度为8', 'min_length': '最小长度为3', 'required': '这个必须填'}, widget=widgets.PasswordInput( attrs={'class': 'form-control', 'placeholder': '请输入密码', 'id': 'pwd'} ) ) re_pwd = forms.CharField( label='确认密码', error_messages={'required': '这个必须填'}, widget=widgets.PasswordInput( attrs={'class': 'form-control', 'placeholder': '请确认密码', 'id': 're_pwd'} ) ) email = forms.EmailField( label='邮箱', error_messages={'invalid': '不符合邮箱格式', 'required': '这个必须填'}, widget=widgets.EmailInput( attrs={'class': 'form-control', 'placeholder': '请输入邮箱', 'id': 'email'} ) ) def clean(self): pwd = self.cleaned_data.get('pwd') re_pwd = self.cleaned_data.get('re_pwd') if pwd == re_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致') def clean_name(self): name = self.cleaned_data.get('name') res = models.User.objects.filter(name=name) if res: raise ValidationError('用户名已经存在') else: return name 各种参数们介绍: forms.CharField 表示该字段为字符类型 EmailField 表示该字段为email类型 max_length=8, min_length=3 对该字段的长度就行限制 label='用户名' , 为该字段添加一个label属性, 在前台渲染时循环这个类的对象可以通过 对象.label 取到这个'用户名'三个字 error_messages={'max_length': '最大长度为8','required': '这个必须填','invalid': '不符合邮箱格式'} 不符合校验规则是给出的提示信息, key为校验规则,value为对应的提示信息 widget: 可以等于以下几个值 1. widgets.PasswordInput() 该输入框为密码类型 2. widgets.TextInput() 该输入框为文本类型 3. 等等 其中在这个括号里面可以为这个文本框添加属性, 如: widget=widgets.TextInput( attrs={'class': 'form-control', 'placeholder': '请输入用户名', 'id': 'name'} )
`
-
注意:需要校验的字段,可以比类的属性多,但是不能少
-
在视图函数里实例化这个类
def index(request): if request.method == 'GET': myform = MyForm() return render(request, 'index.html', locals()) elif request.method == 'POST': #将前台传过来的数据转为字典格式作为参数实例化上面的类,而key与类的属性要对应 #这里因为request.POST是字典格式,且前台传过来时key与属性已经对应了 myform = MyForm(request.POST) #通过校验 if myform.is_valid(): 'myform.is_valid为真, 则数据通过了所有的校验,包括钩子函数的校验' name=self.cleaned_data.get('name') '通过校验的数据在cleaned_data里面' return JsonResponse({'num':200,'mdg':'ok'}) #没通过校验,将错误信息给前台(这里前台是用ajax传的数据,所以这里我用的是JsonResponse) else: return JsonResponse(myform.errors) 错误信息都放在myform.errors,在前台都可以取出来,不记得就console.log一下就可以了 myform.errors是一个字段格式,没通过类的那个属性校验的错误信息是 类的属性名:错误信息 没通过钩子的错误信息是'__all__':错误信息
3. 前端渲染模板与错误信息
-
渲染模板
方式一: 不用for循环 <form action="" method="post" > <p>用户名: {{ myform.name }}</p> <p>密码: {{ myform.pwd }}</p> <p>邮箱: {{ myform.email }}</p> <input type="submit" value="提交"> </form> {{ myform.name }} 这个东西就是一个input框 方式二:for循环form对象(用的比较多): <form action="" method="post" > {% for foo in myform %} <p>{{ foo.label }}:{{ foo }}</p> {% endfor %} <input type="submit" value="提交"> </form> 方式三:(不建议用): <form action="" method="post" > {{ myform.as_ul }} //这里会直接循环成ul>li>input框的形式 {{ myform.as_p }} //这里会直接循环成p>input框的形式 <input type="submit" value="提交"> </form>
-
渲染错误信息
- myforms对象有errors
- 属性(name)也有errors
<span>{{ myform.name.errors.0 }}</span>
钩子
当那些字段的校验规则不能满足时,就用钩子
单个数据用局部钩子, 返回单个数据
用到多个数据时, 用全局钩子, 返回cleaned_data
4. 局部钩子校验
在类中定义一个方法,名字叫:clean_字段名字
,
内部,取出该字段,进行校验,如果通过,将该字段返回,如果失败,抛异常(ValidationError)
注意: 在字段校验完成后才会触发钩子
def clean_name(self):
# self:当前form对象
#程序能走到该函数,前面校验已经通过了,所以可以从cleaned_data中取出数据
name = self.cleaned_data.get('name')
if name.startswith('sb'):
# 失败,抛异常
raise ValidationError('不能以傻逼开头')
# 正常,把name返回
return name
5. 全局钩子
重写clean方法
在类中定义一个方法,名字叫:clean
def clean(self):
pwd = self.cleaned_data.get('pwd')
re_pwd = self.cleaned_data.get('re_pwd')
#进行自己的校验
if pwd == re_pwd:
#通过,直接返回cleaned_data
return self.cleaned_data
else:
#失败,抛异常(ValidationError)
raise ValidationError('两次密码不一致')
坑
局部钩子一定要返回单个数据 , 晚上糊涂了返回了一个cleaned_data
然后,呵呵
cleaned_data里面的name值就是这样的
解释一下就是cleaned_data里面的name又是一个cleaned_data ,这个cleaned_data里面的name又是一个cleaned_data
就是cleaned_data=>name=>cleaned_data=>name=>cleaned_data...
网友评论