the django travel three[form表单验证]

一:表单验证:

场景:因为浏览器的js可以被禁用,所以需要做后台的输入合法的验证。

A:ajax发请求。需要注意的是ajax POST的数据的key值和form表单的里的字段名字一致,否则得不到验证!!!

通过ajax发请求给后端提交数据,然后后端通过form进行输入的验证。

之前ajax POST数据的时候后端需要做如下:

1 def login(request):
2     if request.method=='POST':
3         user=request.POST.get('user')
4         pwd=request.POST.get('pwd   ')
5         print(user,pwd)
6         return HttpResponse('ok')
7     return render(request,'login.html')

1:用form做用户验证的的时候,不需要做这些,直接将request.POST 传入form对象即可获取所有POST数据。

 1 class Loginform(forms.Form):
 2     user=forms.CharField(required=True)#需要继承forms.Form这个模块
 3     pwd=forms.CharField(required=True)#require=True表示该字段不能为空。
 4 
 5 def login(request):
 6     if request.method=='POST':
 7         form_obj=Loginform(request.POST)#获取浏览器提交所有数据
 8         if form_obj.is_valid():#检测POST过来的数据是否符合我们form定义。返回值是bool
 9             data=form_obj.clean()#通过对象的clean()方法来获取用户的提交的数据。
10             print(data)
11             return HttpResponse('ok')
12         else:
13             error=form_obj.errors##通过errors()方法 来获取我们的提交的数据错误提示。这个方法加了装饰器@property变成字段。
14             print(error)
15             return HttpResponse(error)
16     return render(request,'login.html')

前端页面代码:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <script src="/static/js/jquery-1.12.4.js"></script>
 7 </head>
 8 <body>
 9 <div> <input name="user" type="text"></div>
10 <div><input name="pwd" type="password"></div>
11 <div><input type="button" value="提交" onclick="Submit(this)"></div>
12 <script>
13     function Submit(ths) {
14         var data_list={};
15         $('input').each(
16             function (i) {
17                 var name=$(this).attr('name');
18                 var val=$(this).val();
19                 data_list[name]=val;
20             }
21         );
22         $.ajax({
23             url:'/login/',
24             type:'POST',
25             data:data_list,
26             success:function (data) {
27                 console.log(data)
28             },
29             error:function (error) {
30                 console.log(error)
31             }
32         })
33     }
34 </script>
35 </body>
36 </html> 

输出结果:

1 {'pwd': '111', 'user': '111'}
2 <ul class="errorlist"><li>pwd<ul class="errorlist"><li>This field is required.</li></ul></li></ul>

输出打印error对象的类型:

1 <class 'django.forms.utils.ErrorDict'>

可以看出他是一个类对象,我们导入这个对象查看下他的方法:

1             error=form_obj.errors##通过errors()方法 来获取我们的提交的数据错误提示。这个方法加了装饰器@property变成字段。
2             from django.forms.utils import ErrorDict
3             print(type(error))
4             return HttpResponse(error)

查看源码:

 1 @html_safe
 2 @python_2_unicode_compatible
 3 class ErrorDict(dict):
 4     """
 5     A collection of errors that knows how to display itself in various formats.
 6 
 7     The dictionary keys are the field names, and the values are the errors.
 8     """
 9     def as_data(self):
10         return {f: e.as_data() for f, e in self.items()}
11 
12     def as_json(self, escape_html=False):
13         return json.dumps({f: e.get_json_data(escape_html) for f, e in self.items()})
14 
15     def as_ul(self):
16         if not self:
17             return ''
18         return format_html(
19             '<ul class="errorlist">{}</ul>',
20             format_html_join('', '<li>{}{}</li>', ((k, force_text(v)) for k, v in self.items()))
21         )
22 
23     def as_text(self):
24         output = []
25         for field, errors in self.items():
26             output.append('* %s' % field)
27             output.append('\n'.join('  * %s' % e for e in errors))
28         return '\n'.join(output)
29 
30     def __str__(self):
31         return self.as_ul()

我们可以看到当我们print的时候输出的as_ul。错误信息输出有三种数据格式:

1、ul格式,就是之前我们输出的样式:

1 <ul class="errorlist"><li>pwd<ul class="errorlist"><li>This field is required.</li></ul></li></ul>

2:json格式。as_josn.

3:as_text.文本格式。 我们根据我们的需求来获得我们想要的格式。

下面用as_josn来获取我们的错误输出。

 1 def login(request):
 2     if request.method=='POST':
 3         form_obj=Loginform(request.POST)#获取浏览器提交所有数据
 4         if form_obj.is_valid():#检测POST过来的数据是否符合我们form定义。返回值是bool
 5             data=form_obj.clean()#通过对象的clean()方法来获取用户的提交的数据。
 6             print(data)
 7             return HttpResponse('ok')
 8         else:
 9             error=form_obj.errors##通过errors()方法 来获取我们的提交的数据错误提示。这个方法加了装饰器@property变成字段。
10             print(type(error))
11             error_msg=error.as_json()#获取错误信息json格式。
12             print(type(error_msg))
13             return HttpResponse(error_msg)
14     return render(request,'login.html')
1 {"pwd": [{"message": "This field is required.", "code": "required"}], "user": [{"message": "This field is required.", "code": "required"}]}

因为传输的过程是字符串传输,可以在ajax出添加datatype:json来获取json串不需要进行转换。

我们自定义字典,方便我们取值。如上结果我们真正关心的是:“pwd”:[{"message": "This field is required."}]对于code的信息我们不关心。所以定义字典data_dic={"status":false,message:{None}}.

code:

 1 def login(request):
 2     res={'status':False,'message':{}}
 3     if request.method=='POST':
 4         form_obj=Loginform(request.POST)#获取浏览器提交所有数据
 5         if form_obj.is_valid():#检测POST过来的数据是否符合我们form定义。返回值是bool
 6             data=form_obj.clean()#通过对象的clean()方法来获取用户的提交的数据。
 7             print(data)
 8             res['status']=True#符合form规则为true
 9             return HttpResponse('ok')
10         else:
11             error=form_obj.errors##通过errors()方法 来获取我们的提交的数据错误提示。这个方法加了装饰器@property变成字段。
12             error_msg=error.as_json()
13             print(type(error_msg))#as_json转换过来的数据是字符串类型。
14             print(error_msg)
15             res['status']=False#不符合form规则我们定义status为Flase。
16             err_msg=json.loads(error_msg)#将字符串格式的json转换成字典格式,方便我们取值。
17             for  key,val in err_msg.items():
18                 res['message'].setdefault(key,val[0]['message'])#循环取‘user’,‘pwd’对应的报错信息。
19             print(res)
20             return HttpResponse(json.dumps(res))#将json格式的转换成字符串返回给浏览器客户端。
21     return render(request,'login.html')

 

如上所示我们需要给字符串格式的json转成我们处理的数据类型,并取我们想要的值给浏览器返回。

需要注意的是:ajax中指定返回数据类型是dataType是大写的T!!!!!!

页面输出我们错误提示:

前端页面代码:

 1 <body>
 2 <div> <input name="user" type="text"></div>
 3 <div><input name="pwd" type="password"></div>
 4 <div><input type="button" value="提交" onclick="Submit(this)"></div>
 5 <script>
 6     function Submit(ths) {
 7         var data_list={};
 8         $('.error').remove();#每次提交的时候,需要删除错误提示。
 9         $('input').each(
10             function (i) {
11                 var name=$(this).attr('name');
12                 var val=$(this).val();
13                 data_list[name]=val;
14             }
15         );
16         $.ajax({
17             url:'/login/',
18             type:'POST',
19             data:data_list,
20             dataType:'json',
21             success:function (data) {
22                 if(data.status){
23                     void 0
24                 }else {
25                     $.each(
26                             data.message,function(key,val){
27                                 var tag=document.createElement('span');
28                                 tag.innerText=val;
29                                 tag.className='error';###注意不要用id因为一个html文本中id是唯一,他只能删除第一个。
30                                 $('input[name='+key+']').after(tag)
31 
32 
33                             }
34                     );
35                 }
36             },
37             error:function (error) {
38             }
39         })
40     }
41 </script>
42 </body>

效果:

如上代码行:8 需要用class来删除。因为如果用id进行删除的时候会出现:只删除第一个。而且id是唯一不能多次命名,多次提交会出现如下错误:

2:错误信息重写:

一:常规定义错误提示。

错误提示是英文。我们需要把英文错误提示转换成英文提示。

可以在我们后台form类中定义中文如下:

1 class Loginform(forms.Form):
2     user=forms.CharField(required=True,error_messages={'require':"用户名不能为空。"})#需要继承forms.Form这个模块
3     pwd=forms.CharField(required=True)#require=True表示该字段不能为空。

 

因为现在的错误提示是require做的限制。(required=True)。通过变量error_messages来定义错误。字典中key和我们做限制的参数名字一致。

效果:

这是对之前的错误信息重写。

密码错误提示重写。

1 class Loginform(forms.Form):
2     user=forms.CharField(required=True,error_messages={'required':"用户名不能为空。"})#需要继承forms.Form这个模块
3     pwd=forms.CharField(required=True,min_length=6,
4                         max_length=10,
5                         error_messages={'required':'密码不为空!',
6                                         'min_length':'不能少于6位!',
7                                         'max_length':'长度不能超过10位!'})#require=True表示该字段不能为空。 

效果:

二:对django自己做的错误提示重写:

我们添加一列数字,默认required=True。

1 class Loginform(forms.Form):
2     user=forms.CharField(required=True,error_messages={'required':"用户名不能为空。"})#需要继承forms.Form这个模块
3     pwd=forms.CharField(required=True,min_length=6,
4                         max_length=10,
5                         error_messages={'required':'密码不为空!',
6                                         'min_length':'不能少于6位!',
7                                         'max_length':'长度不能超过10位!'})#require=True表示该字段不能为空。
8     num=forms.IntegerField()

 

效果:

我们可以在我们自定义form类中重写这个错误提示。

1 class Loginform(forms.Form):
2     user=forms.CharField(required=True,error_messages={'required':"用户名不能为空。"})#需要继承forms.Form这个模块
3     pwd=forms.CharField(required=True,min_length=6,
4                         max_length=10,
5                         error_messages={'required':'密码不为空!',
6                                         'min_length':'不能少于6位!',
7                                         'max_length':'长度不能超过10位!'})#require=True表示该字段不能为空。
8     num=forms.IntegerField(error_messages={'invalid':'请输入数字!','required':'输入不能为空!'})

效果:

通过:print打印出我们的错误信息吗,到code选项找到那个参数做的限制。

对于第一个不能为空为;required做的限制。

通过后端打印输出error_messages可以看到是那个参数做的限制。

1             error_msg=error.as_json()
2             print(type(error_msg))
3             print(error_msg)

 

还要其他的form验证比如说IP、mail等等!

 三:form验证扩展:如上是form为我们提供了验证。如果form里没有给我们提供验证呢?我们可以自定义验证扩展。

比如手机验证:

 

1 def mobile_validate(value):
2     mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
3     if not mobile_re.match(value):
4         raise ValidationError('手机号码格式错误')

我们可以在我们form类中定义相应的字段,需要导入模块:from django.core.exceptions import ValidationError用参数:validators=[]后面是列表。

code:

 

 1 from django.core.exceptions import ValidationError
 2 import json,re
 3 # Create your views here.
 4 def mobile_validate(value):
 5     mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
 6     if not mobile_re.match(value):
 7         raise ValidationError('手机号码格式错误')
 8 class Loginform(forms.Form):
 9     user=forms.CharField(required=True,error_messages={'required':"用户名不能为空。"})#需要继承forms.Form这个模块
10     pwd=forms.CharField(required=True,min_length=6,
11                         max_length=10,
12                         error_messages={'required':'密码不为空!',
13                                         'min_length':'不能少于6位!',
14                                         'max_length':'长度不能超过10位!'})#require=True表示该字段不能为空。
15     num=forms.IntegerField(error_messages={'invalid':'请输入数字!','required':'输入不能为空!'})
16     phone=forms.CharField(validators=[mobile_validate])#注意的是函数名不是字符串。

我们可以定required的error_message来指定我们想要的内容。

code:

1 phone=forms.CharField(validators=[mobile_validate,],error_messages={'required':'输入不能为空!'})

 

B:当页面有很多数据需要提交和验证,我们不能写每个input标签,当需要修改的时候,我们不能修改每个input标签,于是有第2种方法,form提交数据。

页面代码:

 1 <body >
 2 <div>
 3     <form action="/login/" method="post">
 4         <div>{{obj_form.user }}</div>
 5         {% if obj_form.errors %}
 6         <span>{{ obj_form.errors.user.0}}</span>
 7         {% endif %}
 8         <div>{{ obj_form.pwd }}</div>
 9         {% if obj_form.errors %}
10         <span>{{ obj_form.errors.pwd.0}}</span>
11         {% endif %}
12         <div>{{ obj_form.num }}</div>
13         {% if obj_form.errors %}
14         <span>{{ obj_form.errors.num.0}}</span>
15         {% endif %}
16         <div>{{ obj_form.phone }}</div>
17         {% if obj_form.errors %}
18         <span>{{ obj_form.errors.phone.0}}</span>
19         {% endif %}
20         <div><input type="submit" value="提交" ></div>
21     </form>
22 </div>

 

后台代码:

 1 def login(request):
 2     if request.method=='POST':
 3         obj_login=Loginform(request.POST)
 4         if obj_login.is_valid():
 5             return redirect('/login/')
 6         else:
 7             error=obj_login.errors
 8             print(error['user'][0])
 9             return render(request,'login.html',{'obj_form':obj_login})
10     obj_form_get=Loginform()
11     return render(request,'login.html',{'obj_form':obj_form})

 

总结:

1、form提交验证和ajax提交验证,后台没什么变化,只是前者返回的页面,后者返回的是HttpResponse字符串。

2、form提交的时候,第一次是get请求的,所以第一次的obj_form_get对象内不包含我们提交数据。而POST请求的时候,obj_login对象他包含2部门内容:1:我们在前台表单填写的数据。2:包含我们验证的错误提示。

3、再去错误提示的时候,error默认的数据格式如下:

类似于列表,其中内容部分,是索引为0的字段。所以取值的时候如后台和前台代码那样取值:error['user'][0] 、obj_form.errors.num.0。在js中.点代替python中的[].

4、由于返回页面的时候,默认带有我们添加的<span>标签。所以需要去掉这个标签。

所以在前台页面加入if判断,来确定是否需要添加span标签。

1         {% if obj_form.errors %}
2         <span>{{ obj_form.errors.phone.0}}</span>
3         {% endif %}

C:指定生成特定的标签和属性。

form类中添加相应的属性。

1 test=forms.CharField(widget=forms.TextInput(attrs={'class':'test'}))

在前端显示相应的标签:

1 <div>{{ obj_form.test }}</div>

效果:

也可以生成自定义的属性。或者select标签等。

 1 choice=(
 2     (0,'大连'),
 3     (0,'沈阳'),
 4 )
 5 class Loginform(forms.Form):
 6     user=forms.CharField(required=True,error_messages={'required':"用户名不能为空。"})#需要继承forms.Form这个模块
 7     pwd=forms.CharField(required=True,min_length=6,
 8                         max_length=10,
 9                         error_messages={'required':'密码不为空!',
10                                         'min_length':'不能少于6位!',
11                                         'max_length':'长度不能超过10位!'})#require=True表示该字段不能为空。
12     num=forms.IntegerField(error_messages={'invalid':'请输入数字!','required':'输入不能为空!'})
13     phone=forms.CharField(validators=[mobile_validate,],error_messages={'required':'输入不能为空!'})
14     test=forms.CharField(widget=forms.Select(choices=choice))

 

 

posted @ 2016-09-14 15:18  evil_liu  阅读(259)  评论(0编辑  收藏  举报