● 另一種驗證方法---驗證器(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': ['請輸入正確格式的手機號碼']}
'''