23.Django(form元件 自定製校驗規則、鉤子、更改圖書管理系統)
阿新 • • 發佈:2020-06-29
這些基本你的校驗功能,不足以滿足我們日常的需要,使用者名稱不允許出現敏感字元,電話號碼的驗證,等等。
-
正則校驗器(validators)
name = form.CharField(
label='使用者名稱:',
required=True, #必須填入內容的設定,預設為True
initial='dong', #設定初始值
min_length=6,
max_length=12,
help_text='使用者名稱不能有特殊字元',
# 一個引數正則的匹配規則,第二引數不滿足這個匹配規則報的錯誤資訊
validators=[RegexValidator(r'^金ping梅', '必須以金ping梅開頭'),
errpr_messages={'min_length': '太短了', 'max_length': '太長了',
'required': '必須填寫內容'},
widget=forms.widgets.TextInput,
)這種正則校驗器比較侷限,用起來相對麻煩。
-
自定製函式校驗
(注意:模組的引入要向下面的規則寫)
import re
from django.shortcuts import render, HttpResponse
from django import forms
def moblie_validate(value):
# 我們這裡就給name欄位設定這個函式的的匹配規則
# 那麼這個value就是name欄位實際得到的資料
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 RegisterForm(forms.Form):
"""
form元件生成前端的標籤寫法,與models構建的表結構非常相似
"""
name = forms.CharField(
label='使用者名稱:',
required=True, # 必須填入內容的設定,預設為True
initial='dong', # 設定初始值
min_length=8,
max_length=14,
help_text='使用者名稱不能有特殊字元',
# validators=[RegexValidator(r'^金ping梅', '必須以金ping梅開頭'), RegexValidator(r'xxx$', '必須以xxx結尾')],
error_messages={'min_length': '太短了', 'max_length': '太長了', 'required': '必須填寫內容'},
validators=[moblie_validate],
widget=forms.widgets.TextInput(),
)
password = forms.CharField(
label='密碼:',
min_length=6,
help_text='密碼不得少於8位',
# widget這個功能可以當成一個工具,這個工具就是確認標籤型別以及i增加標籤屬性的
error_messages={'min_length': '太短了'},
widget=forms.widgets.PasswordInput,
)
鉤子
form元件給你提供了另一個自定製校驗規則的介面:區域性鉤子,全域性鉤子
-
區域性鉤子
比如,你的使用者名稱不能出現一些敏感詞彙,敏感詞彙有:
東京熱,蒼⽼師,⾦ping梅,..... 這些⽤正則匹配有點⼉⼒不從⼼了。所以我們就得⽤鉤 ⼦去解決。
區域性鉤子是針對某個欄位校驗的。
import re
from django.shortcuts import render, HttpResponse
from django import forms
from django.core.validators import ValidationError
class RegisterForm(forms.Form):
"""
form元件生成前端的標籤寫法,與models構建的表結構非常相似
"""
name = forms.CharField(
label='使用者名稱:',
required=True, # 必須填入內容的設定,預設為True
initial='dong', # 設定初始值
min_length=8,
max_length=14,
help_text='使用者名稱不能有特殊字元',
# validators=[RegexValidator(r'^金ping梅', '必須以金ping梅開頭'), RegexValidator(r'xxx$', '必須以xxx結尾')],
error_messages={'min_length': '太短了', 'max_length': '太長了', 'required': '必須填寫內容'},
# validators=[moblie_validate],
widget=forms.widgets.TextInput(),
)
password = forms.CharField(
label='密碼:',
min_length=6,
help_text='密碼不得少於8位',
# widget這個功能可以當成一個工具,這個工具就是確認標籤型別以及i增加標籤屬性的
error_messages={'min_length': '太短了'},
widget=forms.widgets.PasswordInput,
)
def clean_name(self): # 針對於name欄位做一個用於校驗的區域性鉤子
print('進入clean_name區域性鉤子')
sensitive_vocabulary = ['京東熱', '蒼老師', '金ping梅']
name_value = self.cleaned_data['name']
for i in sensitive_vocabulary:
if i in name_value:
raise ValidationError(f'含有敏感詞彙{i}')
else:
return self.cleaned_data['name'] # 必須將所有的驗證過後的資料返回
注意:
區域性鉤⼦命名:clean_欄位名
如果有錯誤:主動丟擲異常 ValidationError
校驗成功之後,必須返回self.cleaned_data['欄位名'] -
全域性鉤子
全域性鉤子就是對form類中的所有的欄位做一個對比驗證, 或者橫向驗證。我們一般註冊時,都需要輸入使用者名稱、密碼。再次輸入密碼。這樣的需求在全域性鉤子中做一些驗證比較合適。
import re
from django.shortcuts import render, HttpResponse
from django import forms
from django.core.validators import ValidationError
class RegisterForm(forms.Form):
"""
form元件生成前端的標籤寫法,與models構建的表結構非常相似
"""
name = forms.CharField(
label='使用者名稱:',
required=True, # 必須填入內容的設定,預設為True
initial='dong', # 設定初始值
min_length=8,
max_length=14,
help_text='使用者名稱不能有特殊字元',
# validators=[RegexValidator(r'^金ping梅', '必須以金ping梅開頭'), RegexValidator(r'xxx$', '必須以xxx結尾')],
error_messages={'min_length': '太短了', 'max_length': '太長了', 'required': '必須填寫內容'},
# validators=[moblie_validate],
widget=forms.widgets.TextInput(),
)
password = forms.CharField(
label='密碼:',
min_length=6,
help_text='密碼不得少於8位',
# widget這個功能可以當成一個工具,這個工具就是確認標籤型別以及i增加標籤屬性的
error_messages={'min_length': '太短了'},
widget=forms.widgets.PasswordInput,
)
confirm_password = forms.CharField(
label='再次密碼:',
min_length=6,
help_text='密碼不得少於8位',
# widget這個功能可以當成一個工具,這個工具就是確認標籤型別以及i增加標籤屬性的
error_messages={'min_length': '太短了'},
widget=forms.widgets.PasswordInput,
)
def clean_name(self): # 針對於name欄位做一個用於校驗的區域性鉤子
print('進入clean_name區域性鉤子')
sensitive_vocabulary = ['京東熱', '蒼老師', '金ping梅']
name_value = self.cleaned_data['name']
for i in sensitive_vocabulary:
if i in name_value:
raise ValidationError(f'含有敏感詞彙{i}')
else:
return self.cleaned_data # 必須將所有的驗證過後的資料返回
def clean(self): # 全域性鉤子
v1 = self.cleaned_data['password'],
v2 = self.cleaned_data['confirm_password'],
if v1 == v2:
return self.cleaned_data # 驗證成功必須返回
else:
# confirm_password新增錯誤資訊
self.add_error('confirm_password', '兩次密碼不一樣')
# 主動丟擲一個異常
raise ValidationError('兩次密碼不一樣')
圖書管理系統:
將增加的那個⻚⾯,的前端的標籤,利⽤form元件⾃動⽣成,並且可以進⾏簡單的驗證。
1、在views建立form元件
class BookFrom(forms.Form):
"""
form元件生成前端的標籤
"""
book_name = forms.CharField(
label='書籍名稱:',
required=True,
initial='書名',
min_length=1,
max_length=20,
help_text='書名不能有特殊字元',
error_messages={'min_length': '太短了', 'max_length': '太長了', 'required': '必須填寫內容'},
widget=forms.widgets.TextInput(),
)
book_date = forms.CharField(
label='出版日期:',
widget=forms.widgets.TextInput(attrs={'type': 'date'}), # 標籤型別
)
book_price = forms.DecimalField(
label='書籍價格:',
max_digits=5,
decimal_places=2,
help_text='人民幣(¥)',
widget=forms.widgets.TextInput(attrs={'type': 'number'})
)
book_publish = forms.ChoiceField(
label='出版社:',
initial=1,
choices=((1, 'xx出版社'), (2, 'qq出版社'), (3, 'aa出版社')),
widget=forms.widgets.Select(), # 標籤型別
)
book_author = forms.MultipleChoiceField(
label='作者:',
initial=(1, 2), # 設定初始值
choices=((1, '張三'), (2, '李四'), (3, '王五')),
widget=forms.widgets.SelectMultiple(), # 標籤型別
)
2、更改前端頁面
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="{% static 'bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'dashboard.css' %}" rel="stylesheet">
<style>
#frame {
width: 350px;
height: 400px;
border: 1px solid black;
margin: 180px auto;
}
div {
margin-top: 20px;
margin-left: 20px;
}
.pull {
margin-top: 50px;
margin-left: 150px;
}
select {
margin-left: 17px;
}
</style>
</head>
<body>
<h1>新增書籍頁面</h1>
<div class="row">
<div class="col-md-5 col-md-offset-3">
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
<div>
<label for="">{{ form_obj.book_name.label }}</label>
{{ form_obj.book_name }}
{{ form_obj.book_name.help_text }}
</div>
<div>
<label for="">{{ form_obj.book_date.label }}</label>
{{ form_obj.book_date }}
</div>
<div>
<label for="">{{ form_obj.book_price.label }}</label>
{{ form_obj.book_price }}
{{ form_obj.book_price.help_text }}
</div>
<div>
<label for="">{{ form_obj.book_publish.label }}</label>
{{ form_obj.book_publish }}
</div>
<div>
<label for="">{{ form_obj.book_author.label }}</label>
{{ form_obj.book_author }}
</div>
</form>
</div>
</div>
</body>
</html>
增加bootstrap樣式:
在BookFrom類裡面寫上這個函式:
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
print(self.fields)
for obj in self.fields.values():
obj.widget.attrs.update({'class': 'form-control'})
點選標籤名稱:inptu自動獲取游標
讓label的for = {{ form_obj.欄位名.id_for_label }}
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link href="{% static 'bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'dashboard.css' %}" rel="stylesheet">
<style>
#frame {
width: 350px;
height: 400px;
border: 1px solid black;
margin: 180px auto;
}
div {
margin-top: 20px;
margin-left: 20px;
}
.pull {
margin-top: 50px;
margin-left: 150px;
}
select {
margin-left: 17px;
}
</style>
</head>
<body>
<h1>新增書籍頁面</h1>
<div class="row">
<div class="col-md-5 col-md-offset-3">
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
<div>
<label for="{{ form_obj.book_name.id_for_label }}">{{ form_obj.book_name.label }}</label>
{{ form_obj.book_name }}
{{ form_obj.book_name.help_text }}
</div>
<div>
<label for="{{ form_obj.book_date.id_for_label }}">{{ form_obj.book_date.label }}</label>
{{ form_obj.book_date }}
</div>
<div>
<label for="{{ form_obj.book_price.id_for_label }}">{{ form_obj.book_price.label }}</label>
{{ form_obj.book_price }}
{{ form_obj.book_price.help_text }}
</div>
<div>
<label for="{{ form_obj.book_publish.id_for_label }}">{{ form_obj.book_publish.label }}</label>
{{ form_obj.book_publish }}
</div>
<div>
<label for="{{ form_obj.book_author.id_for_label }}">{{ form_obj.book_author.label }}</label>
{{ form_obj.book_author }}
</div>
</form>
</div>
</div>
</body>
</html>
3、獲取資料的真是出版社以及作者資料
class BookFrom(forms.Form): """ form元件生成前端的標籤 """ book_name = forms.CharField( label='書籍名稱:', required=True, initial='書名', min_length=1, max_length=20, help_text='書名不能有特殊字元', error_messages={'min_length': '太短了', 'max_length': '太長了', 'required': '必須填寫內容'}, widget=forms.widgets.TextInput(), ) book_date = forms.CharField( label='出版日期:', widget=forms.widgets.TextInput(attrs={'type': 'date'}), # 標籤型別 ) book_price = forms.DecimalField( label='書籍價格:', max_digits=5, decimal_places=2, help_text='人民幣(¥)', widget=forms.widgets.TextInput(attrs={'type': 'number'}) ) book_publish = forms.ModelChoiceField( label='出版社:', initial=1, # choices=((1, 'xx出版社'), (2, 'qq出版社'), (3, 'aa出版社')), queryset=models.Publish.objects.all(), widget=forms.widgets.Select(), # 標籤型別 ) book_author = forms.ModelMultipleChoiceField( label='作者:', initial=(1, 2), # 設定初始值 # choices=((1, '張三'), (2, '李四'), (3, '王五')), queryset=models.Author.objects.all(), widget=forms.widgets.SelectMultiple(), # 標籤型別 ) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) print(self.fields) for obj in self.fields.values(): obj.widget.attrs.update({'class': 'form-control'})
4、將post提交的資料寫入資料庫
def add(request): form_obj = BookFrom() if request.method == 'GET': return render(request, 'add.html', {'form_obj': form_obj}) else: form_obj = BookFrom(request.POST) if form_obj.is_valid(): authors = form_obj.cleaned_data.pop('author') book_obj = models.Book.objects.create(**form_obj.cleaned_data) book_obj.author.add(*authors) return redirect('home') else: return render(request, 'add.html', {'form_obj': form_obj})