python測試開發django-114.ModelForm中區域性鉤子(clean_)和全域性鉤子校驗
阿新 • • 發佈:2021-09-04
前言
在實際開發中,不僅僅是對輸入框字元的格式校驗,比如註冊功能,註冊賬號還得校驗資料庫是否已經有賬號被註冊過了。
有些場景不僅僅是對單個輸入框的字元校驗,比如修改密碼的時候,會涉及2個輸入框的資料格式校驗,像這些複雜的場景校驗需用到校驗鉤子來實現。
校驗form表單資料合法性,is_valid()方法呼叫順序:
- 1.欄位規則校驗,字元長度,是否必填等基本校驗
- 2.validators校驗(RegexValidator校驗器或自定義校驗函式)
- 3.區域性鉤子(類中定義的以clean_欄位名命名的函式,校驗正常必須返回該欄位的值self.cleaned_data.get('name'))
- 4.全域性鉤子(類中定義的函式名clean,校驗正常必須返回該物件的校驗結果值return self.cleaned_data)
- 5.每一步通過校驗單結果都以字典形式儲存在類物件的cleaned_data屬性中
ModelForm模型表單
區域性鉤子命名規則為clean_欄位名稱,如:clean_city,clean_years。
super() 重寫__init__
,可以批量更新class屬性。
# 作者-上海悠悠 QQ交流群:717225969 # blog地址 https://www.cnblogs.com/yoyoketang/ class SubmitPageForm(forms.ModelForm): class Meta: model = Submit # fields = "__all__" #全部欄位 fields = ["city", "years", "details"] widgets = { "city": widgets.TextInput(attrs={ "placeholder": "輸入城市:北京/上海/深圳" }), "years": widgets.TextInput(attrs={ "placeholder": "輸入年限"}), "details": widgets.TextInput(attrs={ "placeholder": "輸入詳情"}), } labels = { "city": "城 市", "years": "年 限", "details": "詳 情", } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 批量更新class屬性 for field in self.fields.values(): field.widget.attrs.update({'class': 'form-control'}) def clean_city(self): """區域性鉤子判斷城市必須是北京/上海/深圳其中一個""" city_val = self.cleaned_data.get('city', '') if city_val in ["北京", "上海", "深圳"]: return city_val else: raise forms.ValidationError('城市只能選:北京/上海/深圳')
定義檢視
# 作者-上海悠悠 QQ交流群:717225969 # blog地址 https://www.cnblogs.com/yoyoketang/ class SubmitView(View): def get(self, request): form_obj = SubmitPageForm return render(request, "submit.html", locals()) def post(self, request): form_obj = SubmitPageForm(request.POST) if form_obj.is_valid(): # data = form_obj.cleaned_data() form_obj.save() msg = "儲存成功" return HttpResponseRedirect('/total') else: # 全域性鉤子自定義錯誤提示獲取 # print(form_obj.errors.get('__all__')) # error_msg = form_obj.errors.get('__all__') return render(request, "submit.html", locals())
模板內容
模板內容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>提交頁面</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
<form role="form" action="" method="POST" id="detail-form" >
{% csrf_token %}
{% for field in form_obj %}
<div class="form-group">
{{ field.label_tag }}
{{ field }}
<div style="color: red"> {{ field.errors }} </div>
</div>
{% endfor %}
<p>
<input type="submit" value="提交" >
</p>
</form>
</div>
</body>
</html>
頁面效果
輸入不合法的內容,會顯示field.errors內容
全域性鉤子
針對單個欄位校驗可以用區域性鉤子實現,如果我們要校驗多個欄位,比如校驗註冊的時候輸入2次密碼一致,可以用全域性鉤子實現。
定義全域性鉤子使用clean方法
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/
class SubmitPageForm(forms.ModelForm):
class Meta:
model = Salary
fields = "__all__" #全部欄位
# 省略中間程式碼。。。。。
# 全域性鉤子
def clean(self):
"""在通過基礎驗證的乾淨資料中get獲取欄位"""
pwd1 = self.cleaned_data.get('password')
pwd2 = self.cleaned_data.get('password2')
if pwd1 and pwd2: # 這裡判斷2個欄位都是校驗通過
if pwd1 == pwd2:
# 資料沒問題,那麼原封不動返回即可
return self.cleaned_data
else:
# 錯誤資訊儲存到 errors {'__all__':[e,]}
raise ValidationError('兩次密碼輸入不同')
else:
return self.cleaned_data
前端可以通過fomr_obj.errors.__all__
獲取到內建校驗器的全部錯誤資訊