● 另一种验证方法---验证器(validator),它的效果和'error_messages'参数类似
以下是一些常用的验证器:
<1> MaxValueValidator:验证最大值。
<2> MinValueValidator:验证最小值。
<3> MinLengthValidator:验证最小长度。
<4> MaxLengthValidator:验证最大长度。
<5> EmailValidator:验证是否是邮箱格式。
<6> URLValidator:验证是否是URL格式。
<7> RegexValidator:如果还需要更加复杂的验证,那么我们可以通过正则表达式的验证器:RegexValidator。比如现在要验证手机号码是否合格,那么我们可以通过以下代码实现:
from django import forms
from django.core import validators
class MessageBoardForm(forms.Form):
telephone=forms.CharField(validators=[validators.RegexValidator(r'1[345678]\d{9}',
message='请输入正确格式的手机号码!')])
验证器的基础示例用法:
# forms
from django import forms
from django.core import validators # 导入验证器
class MessageBoardForm(forms.Form):
#email=forms.EmailField(label='邮箱',error_messages=dict(required='必须输入email字段',
#invalid='请输入正确的邮箱地址格式'))
# 通过validators参数指定验证器(list类型,传递message,自定义验证信息)
email=forms.EmailField(validators=[validators.EmailValidator(message='请输入正确的邮箱地址格式')])
# views
from django.shortcuts import render
from django.views.generic import View
from .forms import MessageBoardForm
from django.http import HttpResponse
from django.forms.utils import ErrorDict
class FormView(View):
def get(self,request):
return render(request,'index.html')
def post(self,request):
form=MessageBoardForm(request.POST)
if form.is_valid():
return HttpResponse('数据提交成功!!!')
else:
print(form.errors.get_json_data()) # 依旧调用get_json_data()打印错误信息
return HttpResponse('数据提交失败!')
# index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Message Board</title>
</head>
<body>
<form action="" method="post">
<label> 邮箱:
<input type="text" name="email"> # 单纯弄一个文本框测试效果
</label>
<input type="submit" value="submit">
</form>
</body>
</html>
访问url,随便输入,终端信息:
{'email': [{'message': '请输入正确的邮箱格式', 'code': 'invalid'}]}
换成之前的 error_messages 示例,对比一下效果(基本差不多...):
from django import forms
from django.core import validators
class MessageBoardForm(forms.Form):
email=forms.EmailField(label='邮箱',error_messages=dict(required='必须输入email字段',
invalid='请输入正确的邮箱地址格式'))
# email=forms.EmailField(validators=[validators.EmailValidator(
# message='请输入正确的邮箱地址格式'
# )])
'''
{'email': [{'code': 'invalid', 'message': '请输入正确的邮箱地址格式'}]}
'''
● 自定义验证方法---对字段进行验证(单单有验证器是满足不了需求的)
实现'注册'需求,比如手机号码'telephone'字段值如果已经存在,那就提示'注册失败',终端打印'出错信息'
显然,这个需求得有数据库的支持了...
步骤1: 先定义模型(与前端提交的数据进行比对!)
# front.models
from django.db import models
class User(models.Model):
# 简单定义两个字段
username=models.CharField(max_length=100)
telephone=models.CharField(max_length=11)
# 下面这句其实已经满足需求了,为了演示,就不这么写
#telephone=models.CharField(max_length=11,unique=True)
步骤2: 定义'表单'(代码与'model'类似)
# front.forms
class RegisterForm(forms.Form):
username=forms.CharField(max_length=100)
telephone=forms.CharField(validators=[validators.RegexValidator(
r'1[345678]\d{9}',message='请输入正确格式的手机号码'
)])
步骤3: 后端'views',前端模板编写:
# front.views
class RegisterView(View):
# get加载空表单
def get(self,request):
return render(request,'register.html')
def post(self,request):
form=RegisterForm(request.POST)
if form.is_valid():
username=form.cleaned_data.get('username')
telephone=form.cleaned_data.get('telephone')
# 把获取的字段,传给模型,插入数据库
# 这里暂未涉及对'字段'的判断
User.objects.create(username=username,telephone=telephone)
return HttpResponse('注册成功!')
else:
print(form.errors.get_json_data())
return HttpResponse('注册失败')
# register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post"> # 简单定义一个表单
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>手机号码:</td>
<td><input type="text" name="telephone"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>
上述步骤完成后,刷新网页看看效果,基本的'注册'功能已经有了'雏形',下来,我们对'telephone'字段'自定义验证':
# front.forms
class RegisterForm(forms.Form):
username=forms.CharField(max_length=100)
telephone=forms.CharField(validators=[validators.RegexValidator(
r'1[345678]\d{9}',message='请输入正确格式的手机号码'
)])
def clean_telephone(self): # clean_field()
# 获取telephone字段并与数据库对比
telephone=self.cleaned_data.get('telephone')
exists=User.objects.filter(telephone=telephone).exists()
if exists:
raise forms.ValidationError('{} 已经存在,请变更号码'.format(telephone))
# clean_field()方法一定要返回field...
return telephone
刷新网页,插入相同的'telephone'看看效果
● 批量自定义字段验证---clean()方法的使用
现在要在上述示例的基础上,添加'password'字段的验证,如果两次'password'输入不一致,也提示'注册失败',并且的'终端'打印出'验证失败信息'
class RegisterForm(forms.Form):
username=forms.CharField(max_length=100)
telephone=forms.CharField(validators=[validators.RegexValidator(
r'1[345678]\d{9}',message='请输入正确格式的手机号码'
)])
pw1=forms.CharField(max_length=16,min_length=6) # 新增'密码'字段
pw2=forms.CharField(max_length=16,min_length=6)
def clean_telephone(self):
......
return telephone
# 如果来到了clean()方法,说明之前的每一个字段都验证成功了!
def clean(self):
# 查看源码clean()方法返回的是 self.cleaned_data
clean_data=super().clean() # 调用父类的clean()方法,返回clean_data
pw1=clean_data.get('pw1')
pw2=clean_data.get('pw2')
if pw1 != pw2:
raise forms.ValidationError(message='两次密码输入不一致!')
return clean_data # clean()返回的一定是 clean_data
'''
# 这里这么写也可以
def clean(self):
clean_data=super().clean()
pw1=self.cleaned_data.get('pw1') # 不使用clean_data,而使用self.cleaned_data,一样的效果
pw2=self.cleaned_data.get('pw2')
if pw1!=pw2:
raise forms.ValidationError('两次密码输入不一致,请重新输入')
return clean_data
'''
前端模板修改一下:
# register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>手机号码:</td>
<td><input type="text" name="telephone"></td>
</tr>
<tr>
<td>密码:</td> # 新增passwore文本框,注意type='password'类型
<td><input type="password" name="pw1"></td>
</tr>
<tr>
<td>重复密码:</td>
<td><input type="password" name="pw2"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="提交"></td>
</tr>
</table>
</form>
</body>
</html>
刷新网页,看看'密码不一致'效果
• 需求变更为'用户名'或'手机号码'存在,就提示注册失败,并在终端输出'错误信息',我们使用clean()方法[处理多个字段]一下子搞定[不再定义'clean_field()'对'单独字段'进行处理]
from django import forms
from django.core import validators●
from .models import Register
from django.db.models import Q
class RegiterForm(forms.Form):
username=forms.CharField(max_length=20)
telephone=forms.CharField(validators=[validators.RegexValidator(r'1[345678]\d{9}',
message='请输入正确格式的手机号码!')])
password1=forms.CharField(max_length=16,min_length=6)
password2=forms.CharField(max_length=16,min_length=6)
'''def clean_telephone(self):
telephone=self.cleaned_data.get('telephone')
exists=Register.objects.filter(telephone=telephone).exists()
if exists:
raise forms.ValidationError(message='手机号码已经存在,请变更手机号码!')
return telephone
def clean_username(self):
username=self.cleaned_data.get('username')
exists=Register.objects.filter(username=username).exists()
if exists:
raise forms.ValidationError(message='用户名已经存在,请变更注册名')
return username'''
def clean(self):
clean_data=super().clean()
password1=clean_data.get('password1')
password2=clean_data.get('password2')
username=clean_data.get('username')
telephone=clean_data.get('telephone')
if password1 != password2:
raise forms.ValidationError(message='密码输入不一致,请重新输入!')
exists = Register.objects.filter(Q(telephone=telephone) | Q(username=username)).exists()
if exists:
raise forms.ValidationError(message='用户名或手机号码已经存在,请变更用户名或手机号码!')
return clean_data
什么时候使用clean_field(),什么时候使用clean(),看情况而定了...
● 处理'错误信息',使其显示更加友好,之前的错误信息是这样的:
dict1={'telephone': [{'code': 'invalid', 'message': '请输入正确格式的手机号码'}], '__all__': [{'code': '', 'message': '两次密码输入不一致!'}]}
我们改进一下,变成下面这样的,显然更为'友好':
{'telephone': ['请输入正确格式的手机号码'], '__all__': ['两次密码输入不一致!']}
示例:
# fomrs
from django import forms
from django.core import validators
from .models import User
class RegisterForm(forms.Form):
username=forms.CharField(max_length=100)
......
def clean_telephone(self):
......
return telephone
def clean(self):
......
return clean_data
def get_errors(self):# 自定义get_errors()方法,改进'错误信息'
errors=self.errors.get_json_data() # 调用 get_json_data()方法,获取'信息dict'
new_errors={} # 定义空dict,把改进后的结果,扔进来
for key,message_dicts in errors.items():
messages=[] # 收集字典的'value'值
for message_dict in message_dicts:
message=message_dict['message']
messages.append(message)
new_errors[key]=messages
return new_errors
# views
class RegisterView(View):
def get(self,request):
return render(request,'register.html')
def post(self,request):
......
else:
print(form.get_errors()) # 不再是调用get_json_data()
return HttpResponse('注册失败')
'''
{'__all__': ['两次密码输入不一致!'], 'telephone': ['请输入正确格式的手机号码']}
'''