本節主要介紹一下Django框架表單(Form)的基礎知識。Django框架提供了一系列的工具和庫來幫助設計人員構建表單,透過表單來接收網站使用者的輸入,然後處理以及響應這些使用者的輸入。
6.1.1 HTML表單
Django框架表單是在HTML模板中設計完成的,其實類似於傳統HTML Form表單的應用。在傳統HTML頁面中,表單是由“<form>...</form>”標籤實現的,透過在其中新增相關的一些元素(例如文字輸入框、單選框、核取方塊、文字域、重置按鈕和提交按鈕等),允許終端使用者透過表單輸入相關的資料資訊,然後傳送到服務端(後臺)。Django框架表單也實現了相應的功能,只不過要遵循Django框架標準來設計。
在HTML中,有一些表單元素(例如文字輸入框)是非常簡單且內建於HTML中的,而有一些表單元素會比較複雜(例如日期選擇控制元件、滑塊控制元件等),一般需要透過使用JavaScript、CSS以及<input>等來實現效果。
Django框架表單同樣如此,定義時需要滿足以下兩項常規標準:
負責響應使用者輸入資料的URL地址(action屬性)。
資料請求時使用的HTTP方法(method屬性:GET、POST)。
例如,在Django框架內建的Admin(管理員)登入表單中,就包含如下一些常規<input>元素型別:
使用者名稱:type="text"。
密碼:type="password"。
登入按鈕:type="submit"。
action屬性指定的URL地址:“/admin/”。
method屬性指定的HTTP方法:“POST”。
當使用者單擊<input type="submit" value="Log in">按鈕元素時,提交響應就會被觸發,然後表單資料會被髮送到“/admin/”地址上去。
6.1.2 HTTP方法:GET和POST
Django框架處理表單時只會用到GET和POST這兩種HTTP方法。Django的登入表單需要使用POST方法傳輸資料。當使用POST方法時,瀏覽器會封裝表單資料,為了傳輸安全還會進行必要編碼,然後傳送到服務端並接收其響應。
相比之下,GET方法會將提交的資料繫結到一個字串中,並用該字串來組成一個URL地址。該URL地址包含了資料要傳送的地址以及一些鍵值對應的資料。例如,在Django官方文件(https://docs.djangoproject.com)中進行一次搜尋,就會生成一個類似“https://docs.djangoproject.com/search/?q=forms&release=1”的URL地址,這個就是GET方式。
GET和POST這兩種HTTP方法通常用於不同的目的。任何可能用於更改系統狀態的請求應該使用POST方法,比如一個更改資料庫的請求;GET方法應該只被用於不會影響系統狀態的請求。
還有,GET方法也不適合密碼錶單,因為密碼會出現在URL地址字串中,自然也會被記錄在瀏覽器的歷史記錄以及伺服器的日誌中,而且都是純文字的形式,因此安全性就無法保證。GET方法同樣也不適合處理大量的字串資料或二進位制資料,比如圖片和影片這類的。
在Web應用的管理表單中使用GET請求具有安全隱患:攻擊者很容易透過模擬請求來訪問系統的敏感資料,因此Django Admin模組選擇使用POST方法。在Django框架模板中,POST方法透過與CSRF protection這樣的保護措施配合使用,能對訪問提供更多的控制。
GET方法也不是完全無用武之地的。GET方法適用於類似網頁搜尋表單這樣的場景,這時GET請求的URL地址很容易被儲存為書籤,便於使用者分享或重新提交。因此,在Django官方文件中進行搜尋,就使用了GET方法。
6.1.3 Django在表單中的角色
Django框架處理表單是一件比較複雜的事情。研究一下Django框架的Admin模組,就會發現許多不同型別的資料可能需要在一張表單中完成,然後渲染到HTML模板中呈現,還需要使用便捷的介面進行編輯、上傳到伺服器、驗證和清理資料,最後還要儲存或跳過進行下一步處理。
Django框架的表單功能可以簡化和自動化上述工作的大部分內容,並且也能比大多數設計人員自己編寫程式碼去實現表現得更安全一些。
Django框架會處理涉及表單的3個不同部分:
準備並重組資料,以便下一步的渲染。
為資料建立HTML表單。
接收並處理客戶端提交的表單及資料。
雖然設計人員可以透過手動編寫程式碼來實現上述功能,不過Django框架表單的內建功能已能夠完成這些工作。
6.1.4 Form類
Django框架表單系統的核心元件是Form類,其與Django模型描述物件的邏輯結構、行為以及呈現內容的方式是大致相同的。Form類描述了表單並決定其如何工作以及如何呈現。
類似於模型類的欄位對映到資料庫欄位的方式,ModelForm模型類的欄位會透過表單類的欄位對映到HTML表單的<input>元素中。Django框架的Admin模組就是基於此設計實現的。
表單欄位本身也是類,用於管理表單資料並在提交表單時執行驗證。DateField和FileField處理的資料型別差別很大,所以必須用來處理不同的欄位。
在瀏覽器中,表單欄位以HTML元素(控制元件類)的形式展現。每個欄位型別都有與之相匹配的控制元件類,但必要時可以進行覆蓋。
6.1.5 例項化、處理和渲染表單
在Django框架表單中渲染一個物件的時候,其流程通常如下:
(1)在檢視中獲取物件(例如從資料庫中取出)。
(2)將物件傳遞給模板上下文。
(3)使用模板變數將物件擴充套件為HTML標籤。
在模板中渲染表單與渲染任何其他型別的物件幾乎一樣,但是存在一些關鍵性的差異。
如果模型例項不包含資料,則在模板中對其做任何處理幾乎沒什麼用,但完全有理由來渲染一張空表單,通常當我們希望使用者來填充的時候就會這麼做。因此,當在檢視中處理模型例項時,一般從資料庫中獲取這些物件;當處理表單時,一般在檢視中例項化這些物件。
例項化表單時,可以選擇讓表單為空或預先填充資料,資料來源可以是:
(1)用來儲存模型例項的資料(例如在管理編輯表單的情況下)。
(2)從其他來源獲取的資料。
(3)從前面一個HTML表單提交過來的資料。
6.1.6 建立一個表單
假設希望在網站上建立一個最簡單的表單用來獲取使用者的名字,通常只需要在模板中使用如下類似的程式碼:
【程式碼6-1】
<form action="/get-name/" method="get"> <label for="your_name">Your name: </label> <input id="your_name" type="text" name="your_name" value="{{ current_name }}"> <input type="submit" value="OK"> </form>
【程式碼分析】
在第01行程式碼中,action屬性通知瀏覽器將表單資料提交到URL地址"/get-name/"上,method屬性定義使用GET方法。
在第03行程式碼中,定義了一個<input type="text" />的文字輸入框,用於使用者輸入姓名。同時,value屬性定義為一個上下文變數current_name,如果該變數存在,則其值將會預先填充到表單中。
在第04行程式碼中,定義了一個<input type="submit" />的提交按鈕。
對於【程式碼6-1】中定義的表單,需要一個檢視來渲染這個包含HTML表單的模板,並能提供適當的{{ current_name }}欄位。提交表單時,傳送給伺服器的“GET”請求將包含表單資料。
然後,還需要一個與該URL地址("/get-name/")相對應的檢視,該檢視將在請求中找到相應的鍵-值對,然後對其進行處理。
同時,可能還需要瀏覽器在表單提交之前進行一些欄位驗證,或者使用更復雜的欄位以允許使用者做類似日期選擇的操作等。這時,透過Django框架可以很容易地完成以上大部分工作。