# 第二節:用表單驗證數據
# 用表單驗證數據
## 常用的Field:
使用`Field`可以是對數據驗證的第一步。你期望這個提交上來的數據是什么類型,那么就使用什么類型的`Field`。
### CharField:
用來接收文本。
參數:
- max\_length:這個字段值的最大長度。
- min\_length:這個字段值的最小長度。
- required:這個字段是否是必須的。默認是必須的。
- error\_messages:在某個條件驗證失敗的時候,給出錯誤信息。
### EmailField:
用來接收郵件,會自動驗證郵件是否合法。
錯誤信息的key:`required`、`invalid`。
### FloatField:
用來接收浮點類型,并且如果驗證通過后,會將這個字段的值轉換為浮點類型。
參數:
- max\_value:最大的值。
- min\_value:最小的值。
錯誤信息的key:`required`、`invalid`、`max_value`、`min_value`。
### IntegerField:
用來接收整形,并且驗證通過后,會將這個字段的值轉換為整形。
參數:
- max\_value:最大的值。
- min\_value:最小的值。
錯誤信息的key:`required`、`invalid`、`max_value`、`min_value`。
### URLField:
用來接收`url`格式的字符串。
錯誤信息的key:`required`、`invalid`。
- - - - - -
## 常用驗證器:
在驗證某個字段的時候,可以傳遞一個`validators`參數用來指定驗證器,進一步對數據進行過濾。驗證器有很多,但是很多驗證器我們其實已經通過這個`Field`或者一些參數就可以指定了。比如`EmailValidator`,我們可以通過`EmailField`來指定,比如`MaxValueValidator`,我們可以通過`max_value`參數來指定。以下是一些常用的驗證器:
1. `MaxValueValidator`:驗證最大值。
2. `MinValueValidator`:驗證最小值。
3. `MinLengthValidator`:驗證最小長度。
4. `MaxLengthValidator`:驗證最大長度。
5. `EmailValidator`:驗證是否是郵箱格式。
6. `URLValidator`:驗證是否是`URL`格式。
7. `RegexValidator`:如果還需要更加復雜的驗證,那么我們可以通過正則表達式的驗證器:`RegexValidator`。比如現在要驗證手機號碼是否合格,那么我們可以通過以下代碼實現:```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyForm</span><span class="hljs-params">(forms.Form)</span>:</span>
telephone = forms.CharField(validators=[validators.RegexValidator(<span class="hljs-string">"1[345678]\d{9}"</span>,message=<span class="hljs-string">'請輸入正確格式的手機號碼!'</span>)])
```
```
## 自定義驗證:
有時候對一個字段驗證,不是一個長度,一個正則表達式能夠寫清楚的,還需要一些其他復雜的邏輯,那么我們可以對某個字段,進行自定義的驗證。比如在注冊的表單驗證中,我們想要驗證手機號碼是否已經被注冊過了,那么這時候就需要在數據庫中進行判斷才知道。對某個字段進行自定義的驗證方式是,定義一個方法,這個方法的名字定義規則是:`clean_fieldname`。如果驗證失敗,那么就拋出一個驗證錯誤。比如要驗證用戶表中手機號碼之前是否在數據庫中存在,那么可以通過以下代碼實現:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyForm</span><span class="hljs-params">(forms.Form)</span>:</span>
telephone = forms.CharField(validators=[validators.RegexValidator(<span class="hljs-string">"1[345678]\d{9}"</span>,message=<span class="hljs-string">'請輸入正確格式的手機號碼!'</span>)])
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">clean_telephone</span><span class="hljs-params">(self)</span>:</span>
telephone = self.cleaned_data.get(<span class="hljs-string">'telephone'</span>)
exists = User.objects.filter(telephone=telephone).exists()
<span class="hljs-keyword">if</span> exists:
<span class="hljs-keyword">raise</span> forms.ValidationError(<span class="hljs-string">"手機號碼已經存在!"</span>)
<span class="hljs-keyword">return</span> telephone
```
```
以上是對某個字段進行驗證,如果驗證數據的時候,需要針對多個字段進行驗證,那么可以重寫`clean`方法。比如要在注冊的時候,要判斷提交的兩個密碼是否相等。那么可以使用以下代碼來完成:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyForm</span><span class="hljs-params">(forms.Form)</span>:</span>
telephone = forms.CharField(validators=[validators.RegexValidator(<span class="hljs-string">"1[345678]\d{9}"</span>,message=<span class="hljs-string">'請輸入正確格式的手機號碼!'</span>)])
pwd1 = forms.CharField(max_length=<span class="hljs-params">12</span>)
pwd2 = forms.CharField(max_length=<span class="hljs-params">12</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">clean</span><span class="hljs-params">(self)</span>:</span>
cleaned_data = super().clean()
pwd1 = cleaned_data.get(<span class="hljs-string">'pwd1'</span>)
pwd2 = cleaned_data.get(<span class="hljs-string">'pwd2'</span>)
<span class="hljs-keyword">if</span> pwd1 != pwd2:
<span class="hljs-keyword">raise</span> forms.ValidationError(<span class="hljs-string">'兩個密碼不一致!'</span>)
```
```
## 提取錯誤信息:
如果驗證失敗了,那么有一些錯誤信息是我們需要傳給前端的。這時候我們可以通過以下屬性來獲取:
1. `form.errors`:這個屬性獲取的錯誤信息是一個包含了`html`標簽的錯誤信息。
2. `form.errors.get_json_data()`:這個方法獲取到的是一個字典類型的錯誤信息。將某個字段的名字作為`key`,錯誤信息作為值的一個字典。
3. `form.as_json()`:這個方法是將`form.get_json_data()`返回的字典`dump`成`json`格式的字符串,方便進行傳輸。
4. 上述方法獲取的字段的錯誤值,都是一個比較復雜的數據。比如以下:
```
<pre class="calibre12">```
{<span class="hljs-string">'username'</span>: [{<span class="hljs-string">'message'</span>: <span class="hljs-string">'Enter a valid URL.'</span>, <span class="hljs-string">'code'</span>: <span class="hljs-string">'invalid'</span>}, {<span class="hljs-string">'message'</span>: <span class="hljs-string">'Ensure this value has at most 4 characters (it has 22).'</span>, <span class="hljs-string">'code'</span>: <span class="hljs-string">'max_length'</span>}]}
```
```
那么如果我只想把錯誤信息放在一個列表中,而不要再放在一個字典中。這時候我們可以定義一個方法,把這個數據重新整理一份。實例代碼如下:
```
<pre class="calibre12">```
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MyForm</span><span class="hljs-params">(forms.Form)</span>:</span>
username = forms.URLField(max_length=<span class="hljs-params">4</span>)
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_errors</span><span class="hljs-params">(self)</span>:</span>
errors = self.errors.get_json_data()
new_errors = {}
<span class="hljs-keyword">for</span> key,message_dicts <span class="hljs-keyword">in</span> errors.items():
messages = []
<span class="hljs-keyword">for</span> message <span class="hljs-keyword">in</span> message_dicts:
messages.append(message[<span class="hljs-string">'message'</span>])
new_errors[key] = messages
<span class="hljs-keyword">return</span> new_errors
```
```
這樣就可以把某個字段所有的錯誤信息直接放在這個列表中。
- Introduction
- 第一章:學前準備
- 第一節:虛擬環境
- 第二節:準備工作
- 第三節:Django介紹
- 第四節:URL組成部分
- 第二章:URL與視圖
- 第一節:第一個Django項目
- 第二節:視圖與URL分發器
- 第三章:模板
- 第一節:模板介紹
- 第二節:模板變量
- 第三節:常用標簽
- 第四節:常用過濾器
- 第五節:自定義過濾器
- 第七節:模版結構優化
- 第八節:加載靜態文件
- 第四章:數據庫
- 第一節:MySQL相關軟件
- 第二節:數據庫操作
- 第三節:ORM模型
- 第四節:模型常用字段
- 第五節:外鍵和表關系
- 第六節:增刪改查操作
- 第七節:查詢操作
- 第八節:QuerySet API
- 第九節:ORM模型遷移
- 第十節:ORM作業
- 第十一節:ORM作業參考答案
- 第十二節:Pycharm連接數據庫
- 第五章:視圖高級
- 第一節:限制請求method
- 第二節:頁面重定向
- 第三節:HttpRequest對象
- 第四節:HttpResponse對象
- 第五節:生成CSV文件
- 第六節:類視圖
- 第七節:錯誤處理
- 第六章:表單
- 第一節:表單概述
- 第二節:用表單驗證數據
- 第三節:ModelForm
- 第四節:文件上傳
- 第七章:cookie和session
- 第八章:上下文處理器和中間件
- 第一節:上下文處理器
- 第二節:中間件
- 第九章:安全
- 第一節:CSRF攻擊
- 第二節:XSS攻擊
- 第三節:點擊劫持攻擊
- 第四節:SQL注入
- 第十章:信號
- 第一節:什么是信號
- 第十一章:驗證和授權
- 第一節:概述
- 第二節:用戶對象
- 第三節:權限和分組
- 第十二章:Admin系統
- 第十三章:Django的緩存
- 第十四章:memcached
- 第十五章:Redis