Django之表单验证
目录:
form表单验证
Django自带表单验证功能。
表单验证的实现
urls路由
urlpatterns = [
url(r'articles/(?P<year>[0-9]{4})/$', views.year_archive,{ 'mouth': '09' }),
url(r'add/$', views.add),
url(r'form1/$', views.form1),
]
views视图(业务逻辑)
from forms import Form1
from django.shortcuts import render
def form1(request):
if request.method == 'POST':
request.POST.get('username',None)
request.POST.get('password',None)
# 获取请求内容进行验证
f = Form1(request.POST)
ret = f.is_valid()
print ret
return render(request, 'form.html')
form表单
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
class Form1(forms.Form):
name = forms.CharField()
password = forms.CharField()
template的form.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app/form1/" method="post">
<div>
<input type="text" name="username">
</div>
<div>
<input type="text" name="password">
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
获取验证结果
直接什么都不输入进行访问
直接进行访问
后端print的结果
False
[10/Oct/2017 00:13:43] "POST /app/form1/ HTTP/1.1" 200 418
输入字段
True
[10/Oct/2017 00:25:08] "POST /app/form1/ HTTP/1.1" 200 418
获取错误信息
def form1(request):
if request.method == 'POST':
request.POST.get('username',None)
request.POST.get('password',None)
# 获取请求内容进行验证
f = Form1(request.POST)
if f.is_valid():
print f.cleaned_data
else:
print f.errors
print type(f.errors)
return render(request, 'form.html')
输入字段
{'username': u'123', 'password': u'123'}
[10/Oct/2017 00:26:36] "POST /app/form1/ HTTP/1.1" 200 418
直接进行访问
<ul class="errorlist"><li>username<ul class="errorlist"><li>This field is required.</li></ul></li><li>password<ul class="errorlist"><li>This field is required.</li></ul></li></ul>
<class 'django.forms.utils.ErrorDict'>
[10/Oct/2017 00:26:47] "POST /app/form1/ HTTP/1.1" 200 418
错误返回到前端
form.html使用一个模板进行接收
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ error }}
<form action="/app/form1/" method="post">
<div>
<input type="text" name="username">
</div>
<div>
<input type="text" name="password">
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
form.py将error通过render传递到前端。
def form1(request):
if request.method == 'POST':
request.POST.get('username',None)
request.POST.get('password',None)
# 获取请求内容进行验证
f = Form1(request.POST)
if f.is_valid():
print f.cleaned_data
else:
print f.errors
print type(f.errors)
return render(request, 'form.html',{'error':f.errors})
return render(request, 'form.html')
当然也可以返回locals(),代表当前所有局部变量
不进行输入,前端和可以直接获取到
不过被封装在ul和li中了,自定义一下
def form1(request):
if request.method == 'POST':
request.POST.get('username',None)
request.POST.get('password',None)
# 获取请求内容进行验证
f = Form1(request.POST)
if f.is_valid():
print f.cleaned_data
else:
print f.errors['username'][0]
print f.errors['password'][0]
return render(request, 'form.html',{'error':f.errors})
return render(request, 'form.html')
可以看到以下情况
This field is required.
This field is required.
有个问题,如果error中没有username这个key。
def form1(request):
if request.method == 'POST':
request.POST.get('username',None)
request.POST.get('password',None)
# 获取请求内容进行验证
f = Form1(request.POST)
if f.is_valid():
print f.cleaned_data
else:
print f.errors.get('username',None)
print f.errors.get('password',None)
return render(request, 'form.html',{'error':f.errors})
return render(request, 'form.html')
None
<ul class="errorlist"><li>This field is required.</li></ul>
分开显示
放到html对应位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app/form1/" method="post">
<div>
<input type="text" name="username">
<span>{{ error.username }}</span>
</div>
<div>
<input type="text" name="password">
<span>{{ error.password }}</span>
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
进行访问
前端显示
浏览器的前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/app/form1/" method="post">
<div>
<input type="text" name="username">
<span>{{ error.username.0 }}</span>
</div>
<div>
<input type="text" name="password">
<span>{{ error.password.0 }}</span>
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
添加样式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.input-group {
position: relative;
padding: 20px;
width: 250px;
}
.input-group input{
width: 200px;
display: inline-block;
}
.input-group span{
display: inline-block;
position: absolute;
height: 12px;
font-size: 8px;
border: 1px solid darkred;
background-color: coral;
color: white;
top: 41px;
left: 20px;
width: 202px;
}
</style>
</head>
<body>
<form action="/app/form1/" method="post">
<div class="input-group">
<input type="text" name="username">
<span>{{ error.username.0 }}</span>
</div>
<div class="input-group">
<input type="text" name="password">
<span>{{ error.password.0 }}</span>
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
前端展示
浏览器前端代码
不异常的时候不进行显示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.input-group {
position: relative;
padding: 20px;
width: 250px;
}
.input-group input{
width: 200px;
display: inline-block;
}
.input-group span{
display: inline-block;
position: absolute;
height: 12px;
font-size: 8px;
border: 1px solid darkred;
background-color: coral;
color: white;
top: 41px;
left: 20px;
width: 202px;
}
</style>
</head>
<body>
<form action="/app/form1/" method="post">
<div class="input-group">
<input type="text" name="username">
{% if error.username.0 %}
<span>{{ error.username.0 }}</span>
{% endif %}
</div>
<div class="input-group">
<input type="text" name="password">
{% if error.password.0 %}
<span>{{ error.password.0 }}</span>
{% endif %}
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
会有一个问题,提交的数据没有通过验证,新的页面刚才添加的数据都没有了
使用form自动生成input标签
def form1(request):
f = Form1()
if request.method == 'POST':
request.POST.get('username',None)
request.POST.get('password',None)
# 获取请求内容进行验证
f = Form1(request.POST)
return render(request, 'form.html',{'error':f.errors,'form': f})
return render(request, 'form.html', {'form': f})
当然这里只考虑了验证失败的情况,成功肯定是做跳转了,就省略掉了
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.input-group {
position: relative;
padding: 20px;
width: 250px;
}
.input-group input{
width: 200px;
display: inline-block;
}
.input-group span{
display: inline-block;
position: absolute;
height: 12px;
font-size: 8px;
border: 1px solid darkred;
background-color: coral;
color: white;
top: 41px;
left: 20px;
width: 202px;
}
</style>
</head>
<body>
<form action="/app/form1/" method="post" novalidate>
<div class="input-group">
{{ form.username }}
{% if error.username.0 %}
<span>{{ error.username.0 }}</span>
{% endif %}
</div>
<div class="input-group">
{{ form.password }}
{% if error.password.0 %}
<span>{{ error.password.0 }}</span>
{% endif %}
</div>
<div>
<input type="submit" value="提交">
</div>
</form>
</body>
</html>
可以看到自动生成的input标签
对于只输入username的返回页面
注意要有form里要有novalidate,这个是html5给form元素新增了一个novalidate属性,指定为true或者就直接仅仅声明这个属性的时候,不会验证字段
否则会出现以下情况
对于默认required=True,也就是不允许为空
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
class Form1(forms.Form):
username = forms.CharField(required=False)
password = forms.CharField()
字段
- max_length 最大长度
- min_length 最小长度
- error_messages 错误信息
- required 是否可以为空
- widget 样式
自定义错误信息
form.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
class Form1(forms.Form):
username = forms.CharField(required=False)
password = forms.CharField()
email = forms.EmailField(error_messages={'required': '邮箱不能为空','invalid': '邮箱格式错误'})
form.html
<div class="input-group">
{{ form.email }}
{% if error.email.0 %}
<span>{{ error.email.0 }}</span>
{% endif %}
</div>
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
class Form1(forms.Form):
username = forms.CharField(required=False)
password = forms.CharField()
email = forms.EmailField(error_messages={'required': '邮箱不能为空','invalid': '邮箱格式错误'})
自定义样式
默认情况下为widget=forms.TextInput()
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
class Form1(forms.Form):
username = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'why'}))
password = forms.CharField()
email = forms.EmailField(error_messages={'required': '邮箱不能为空','invalid': '邮箱格式错误'})
前端可以看到textarea格式的输入框
前端代码
自定义选项框
可以直接定义选项框数据,但是这样有局限性,可以从数据库拿,下边就直接展示显示从数据库获取数据
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
from models import UserGroup
class Form1(forms.Form):
username = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'why'}))
password = forms.CharField()
email = forms.EmailField(error_messages={'required': '邮箱不能为空','invalid': '邮箱格式错误'})
usertype_choice = UserGroup.objects.values_list("id", "caption")
print usertype_choice
usertype = forms.CharField(widget=forms.widgets.Select(choices=usertype_choice, attrs={'class': "form-control"}))
添加字段
<div class="input-group">
{{ form.usertype }}
{% if error.usertype.0 %}
<span>{{ error.usertype.0 }}</span>
{% endif %}
</div>
前端效果
数据库数据
mysql> select * from app_usergroup;
+----+---------+
| id | caption |
+----+---------+
| 1 | ops |
| 2 | dev |
| 3 | test |
+----+---------+
3 rows in set (0.00 sec)
mysql> insert into app_usergroup (caption) values ('admin');
Query OK, 1 row affected (0.01 sec)
mysql> select * from app_usergroup;
+----+---------+
| id | caption |
+----+---------+
| 1 | ops |
| 2 | dev |
| 3 | test |
| 4 | admin |
+----+---------+
4 rows in set (0.00 sec)
可以看到,添加了新数据,但是前端首页
但是添加了新的数据,没有显示,重启才能生效
因为这个是一个类的静态字段,在进行解释的时候就被调用,生成的时候就被创建,保持不变,所以在数据库中添加了是不会生效,就需要改成一个动态字段,在每次生成类的时候调用一次
下边代码进行了动态的绑定
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
from models import UserGroup
class Form1(forms.Form):
username = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'why'}))
password = forms.CharField()
email = forms.EmailField(error_messages={'required': '邮箱不能为空','invalid': '邮箱格式错误'})
# usertype_choice = UserGroup.objects.values_list("id", "caption")
# usertype = forms.CharField(widget=forms.widgets.Select(choices=usertype_choice, attrs={'class': "form-control"}))
def __init__(self, *args, **kwargs):
super(Form1, self).__init__(*args, **kwargs)
self.fields['usertype'] = forms.CharField(
widget=forms.widgets.Select(choices=UserGroup.objects.values_list("id", "caption"), attrs={'class': "form-control"})
)
再度修改数据库数据
mysql> insert into app_usergroup (caption) values ('member');
Query OK, 1 row affected (0.01 sec)
可以看到新生成的数据已经出现在选项框中
自定义验证规则
<div class="input-group">
{{ form.phone }}
{% if error.phone.0 %}
<span>{{ error.phone.0 }}</span>
{% endif %}
</div>
对于自定义验证信息需要进行方法的创建
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django import forms
from models import UserGroup
import re
from django.core.exceptions import ValidationError
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 Form1(forms.Form):
username = forms.CharField(required=False, widget=forms.Textarea(attrs={'class':'why'}))
password = forms.CharField()
email = forms.EmailField(error_messages={'required': '邮箱不能为空','invalid': '邮箱格式错误'})
phone = forms.CharField(validators=[mobile_validate, ],
error_messages={'required': u'手机不能为空'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))
def __init__(self, *args, **kwargs):
super(Form1, self).__init__(*args, **kwargs)
self.fields['usertype'] = forms.CharField(
widget=forms.widgets.Select(choices=UserGroup.objects.values_list("id", "caption"), attrs={'class': "form-control"})
)
进行错误提交的返回
进行正确提交的返回
对于ajax请求
对于ajax,需要根据error构造合适的返回值了。
参考代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
from django import forms
from django.core.exceptions import ValidationError
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 PublishForm(forms.Form):
user_type_choice = (
(0, u'普通用户'),
(1, u'高级用户'),
)
user_type = forms.IntegerField(widget=forms.widgets.Select(choices=user_type_choice,
attrs={'class': "form-control"}))
title = forms.CharField(max_length=20,
min_length=5,
error_messages={'required': u'标题不能为空',
'min_length': u'标题最少为5个字符',
'max_length': u'标题最多为20个字符'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': u'标题5-20个字符'}))
memo = forms.CharField(required=False,
max_length=256,
widget=forms.widgets.Textarea(attrs={'class': "form-control no-radius", 'placeholder': u'详细描述', 'rows': 3}))
phone = forms.CharField(validators=[mobile_validate, ],
error_messages={'required': u'手机不能为空'},
widget=forms.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))
email = forms.EmailField(required=False,
error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
widget=forms.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
代码摘自Python之路【第十七篇】:Django【进阶篇 】
触发Model中的验证和错误提示有两种方式:
- Django Admin中的错误信息会优先根据Admin内部的ModelForm错误信息提示,如果都成功,才来检查Model的字段并显示指定错误信息
- 调用Model对象的 clean_fields 方法
For example:
# models.py
class UserInfo(models.Model):
nid = models.AutoField(primary_key=True)
username = models.CharField(max_length=32)
email = models.EmailField(error_messages={'invalid': '格式错了.'})
# views.py
def index(request):
obj = models.UserInfo(username='11234', email='uu')
try:
print(obj.clean_fields())
except Exception as e:
print(e)
return HttpResponse('ok')
# Model的clean方法是一个钩子,可用于定制操作,如:上述的异常处理。
Admin中修改错误提示
# admin.py
from django.contrib import admin
from model_club import models
from django import forms
class UserInfoForm(forms.ModelForm):
username = forms.CharField(error_messages={'required': '用户名不能为空.'})
email = forms.EmailField(error_messages={'invalid': '邮箱格式错误.'})
age = forms.IntegerField(initial=1, error_messages={'required': '请输入数值.', 'invalid': '年龄必须为数值.'})
class Meta:
model = models.UserInfo
# fields = ('username',)
fields = "__all__"
class UserInfoAdmin(admin.ModelAdmin):
form = UserInfoForm
admin.site.register(models.UserInfo, UserInfoAdmin)