Python菜鸟之路:Django 表单验证

时间:2023-03-10 02:53:46
Python菜鸟之路:Django 表单验证

前言

  Django中完成表单验证,常用的有两种方法:

  一种是通过HTML + JS + Ajax实现。

  另一种是通过Django自身的forms模块来生成相应个HTML标签来完成表单验证。这是本节着重讲的地方

第一种方法:html + ajax实现基本的login页面

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
.error-msg{
color: red;
}
</style>
</head>
<body>
<div>
<div>
<input type="text" name="user" /> </div>
<div>
<input type="password" name="pwd" />
</div>
<div>
<input type="text" name="num" />
</div>
<div>
<input type="text" name="phone" />
</div>
<input type="button" value="提交" onclick="DoSubmit();" />
</div>
<script src="/static/jquery-2.1.4.min.js"></script>
<script>
function DoSubmit(){
var input_dict = {};
$('input').each(function(){
var v = $(this).val();
var n = $(this).attr('name');
input_dict[n] = v;
});
console.log(input_dict);
$('.error-msg').remove();
$.ajax({
url: '/login/',
type: 'POST',
data: input_dict,
dataType: 'json',
success: function (result) {
if(result.status){
location.href = '/index/';
}else{ $.each(result.message, function (k,v) {
console.log(k,v[0].message);
// <span class="error-msg">错误信息</span>
var tag = document.createElement('span');
tag.className = 'error-msg';
tag.innerText = v[0].message;
// input[name="user"]
$('input[name="' + k + '"]').after(tag);
})
}
},
error: function () { }
})
}
</script>
</body>
</html>

HTML代码

from django.shortcuts import render,HttpResponse

# Create your views here.
from django import forms
from django.core.exceptions import ValidationError
import re def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') class LoginForm(forms.Form):
user = forms.CharField(required=True, error_messages={'required': '用户名不能为空.'})
pwd = forms.CharField(required=True,
min_length=6,
max_length=10,
error_messages={'required': '密码不能为空.', 'min_length': "至少6位"})
num = forms.IntegerField(error_messages={'required': '数字不能空.','invalid': '必须输入数字'})
phone = forms.CharField(validators=[mobile_validate, ],) import json
def login(request):
if request.method == 'POST':
result = {'status': False, 'message': None}
obj = LoginForm(request.POST)
ret = obj.is_valid()
if ret:
print(obj.clean())
result['status'] = True
else:
from django.forms.utils import ErrorDict
#print(type(obj.errors),obj.errors.as_json())
error_str = obj.errors.as_json()
result['message'] = json.loads(error_str)
return HttpResponse(json.dumps(result))
return render(request, 'login.html')

views代码

  这里边views中,已经用到了django自带的forms模块。在不用这个模块之前,我们对于用户输入进行判断,需要一堆的if..if...if语句来进行,但是用了这个模块之后,仅需要在定义好LoginForm类中每个字段的属性后,通过obj = LoginForm(request.POST)和ret = obj.is_valid()两步,就可以完成对于用户输入信息的验证。ret会返回验证是否全部通过。全部通过则为True,只要有一条表单信息验证不通过,则为False。

这里需要关注的知识点是:obj.clean() 是输出用户post的正确信息,是一个dict,obj.errors是输出用户post的错误信息,是一个通过ul li显示的信息,这样不方便查看。可以通过obj.errors.as_json()来将错误信息以json形式展示,用error_str = obj.errors.as_json() 和 result['message'] = json.loads(error_str)来完成错误信息收集。

  另外定义表单验证规则LoginForm类时,字段名需要等于html中name值

  补充知识点:在定义的LoginForm中,定义的pwd字段是这样定义的

pwd = forms.CharField(required=True,
min_length=6,
max_length=10,
error_messages={'required': '密码不能为空.', 'min_length': "至少6位"})

  其中error_messages属性是用来定义错误信息的展示的。解释为:如果required验证不通过,则提示'密码不能为空',min_length验证不通过,则错误信息为'至少6位'。扩展'invalid': '必须输入数字'

第二种方法:利用forms模块生成html标签

  forms能解决的2个问题:

  问题1: 如果使用html自带的form标签来进行提交,如果提交的数据有错误,会清空表单中的全部数据,如果表单项较多,对用户非常不友好。那么forms模块就能解决这个问题。

问题2: 使用html的form标签提交数据,需要input标签的name属性必须和定义的class类的属性一致。而使用django forms模块,则不需要考虑这个问题。

废话不多说,直接贴代码

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
.error-msg{
color: red;
}
</style>
</head>
<body>
<form action="/login/" method="POST">
<div>
<div>
{{ obj1.user }}
{% if obj1.errors.user %}
<span class="error-msg">{{ obj1.errors.user.0 }}</span>
{% endif %}
</div>
<div>
{{ obj1.pwd }}
<span class="error-msg">{{ obj1.errors.pwd.0 }}</span>
</div>
<div>
{{ obj1.num }}
<span class="error-msg">{{ obj1.errors.num.0 }}</span>
</div>
<div>
{{ obj1.phone }}
<span class="error-msg">{{ obj1.errors.phone.0 }}</span>
</div>
<div>
{{ obj1.test }}
<span class="error-msg">{{ obj1.errors.test.0 }}</span>
</div>
<input type="submit" value="提交" />
</div>
</form>
</body>
</html>

login.html

后端代码

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from django import forms
from django.core.exceptions import ValidationError
import re
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') class LoginForm(forms.Form):
user = forms.CharField(required=True, error_messages={'required': '用户名不能为空.'})
pwd = forms.CharField(required=True,
min_length=6,
max_length=10,
error_messages={'required': '密码不能为空.', 'min_length': "至少6位"}) num = forms.IntegerField(error_messages={'required': '数字不能空.','invalid': '必须输入数字'}) phone = forms.CharField(validators=[mobile_validate, ],) #test = forms.CharField(widget=forms.Textarea(attrs={'class': 'c1'}))
test_choices = (
(0, '上海'),
(1, '背景'),
)
test = forms.IntegerField(widget=forms.Select(choices=test_choices)) def login(request):
if request.POST:
objPost = LoginForm(request.POST)
ret = objPost.is_valid()
if ret:
print(objPost.clean())
else:
from django.forms.utils import ErrorDict
#print(type(obj.errors),obj.errors.as_json())
# obj1.errors
pass
return render(request, 'login.html',{'obj1': objPost})
else:
objGet = LoginForm()
return render(request, 'login.html',{'obj1': objGet})

views.py

from django.conf.urls import url

from app01 import views

urlpatterns = [

    url(r'^login/', views.login),

]

urls.py

知识点:如何生成自定义的标签类型

  forms默认帮我们生成的是INPUT标签,同时也支持生成其他标签。在源代码中,可以看到支持很多的Field类型

          Python菜鸟之路:Django 表单验证Python菜鸟之路:Django 表单验证

  上边的一堆类可以看出,继承Field的类,可以用作生成标签,这些类都写在fields.py文件中。而forms.IntegerField(widget=forms.Select(choices=test_choices)中的widget字段中的类,都需要继承自Widget才可以,这些类都写在widgets.py中。

  比如,如果生成下拉框可以这么写:

    test_choices = (
(0, '上海'),
(1, '背景'),
)
test = forms.IntegerField(widget=forms.Select(choices=test_choices))

知识点:如何给生成的标签自定义属性

 test = forms.CharField(widget=forms.Textarea(attrs={'class': 'c1'}))