概述
在前壹章中,我們為主頁定義了壹個簡單的模板,壹些未實現的模塊(如用戶或帖子)使用模擬對象作為臨時占位符。
在本章中,我們將看到如何使用web表單來填補這些空白。
Web表單是web應用程序中最基本的構建元素,我們將通過表單實現用戶發帖和應用程序登錄的功能。
要完成本章,您需要基於上壹章的微博應用程序代碼。請確認這些代碼已經安裝並且可以正常運行。
部署
Flask-WTF是WTForms項目的Flask框架的擴展,我們將使用它來幫助我們處理web表單。
大多數Flask擴展都需要定義相關的配置項,因此讓我們首先在應用程序根目錄中創建壹個配置文件以供使用。讓我們首先像這樣創建(fileconfig.py ):
SRF_ENABLED = True
SECRET_KEY =妳永遠猜不到
很簡單,對嗎?這是Flask-WTF需要使用的兩個配置項。CSRF啟用配置支持跨站點請求攻擊防護。在大多數情況下,您需要打開此功能,這可以使您的應用程序更加安全。
SECRET_KEY設置在啟用CSRF時有效,這將生成壹個用於表單驗證的加密令牌。您應該確保該密鑰足夠復雜,不會被簡單地猜到。
現在這個配置文件基本上是可用的。創建項目後,我們可以創建以下文件並編輯它們(fileapp/__init__)。py):
從燒瓶導入燒瓶
app = Flask(_ _ name _ _)
app.config.from_object(配置)
從應用程序導入視圖
用戶登錄表單
用Flask-WTF創建的表單就像壹個對象,它需要從Form類繼承子類。然後在這個子類中定義壹些類屬性變量作為表單字段。
我們需要創建壹個登錄表單用於用戶識別。但是,與通常需要驗證用戶名和密碼的登錄方法不同,我們將使用OpenId來處理登錄過程。使用OpenId的好處是,我們不必擔心用戶名和密碼的身份驗證過程,並將其留給OpenId,它會將驗證過的數據返回給我們的用戶。這對使用我們網站的用戶來說也更安全。
用OpenId登錄只需要壹個字符串,然後將其發送到OpenId服務器。此外,我們需要在表單中添加壹個“記住我”選項框,這是為那些不想每次訪問我們的網站時都進行身份驗證的人準備的。選擇此選項後,他們將在首次登錄時使用cookie在瀏覽器上記住他們的登錄信息,下次進入網站時無需登錄。
讓我們開始第壹個表單(fileapp/forms.py):
從flask.ext.wtf導入表單,TextField,BooleanField
需要從flask.ext.wtf導入
類邏輯信息格式(格式):
OpenID = TextField(OpenID,validators =【Required()】)
remember _ me = boolean field(remember _ me,default = False)
欣賞這堂課,多麽簡單明了。如此簡單,卻內涵十分豐富。我們引入了壹個表單類,然後繼承了它,並根據需要添加了兩個字段:TextField和BooleanField。
此外,還引入了所需的表單驗證功能,該功能可以附加到字段中,用於檢查用戶提交表單時填寫的數據。這個必需的函數用於防止用戶提交空數據。Flask-WTF中有許多具有不同功能的表單驗證函數,我們稍後將使用它們。
表單模板
現在我們的問題是我們需要壹個模板來顯示這個登錄表單。好消息是我們剛剛創建的登錄表單類知道如何將字段轉換為HTML,因此我們只需要關註頁面布局。以下是我們登錄表單的模板(fileapp/templates/login.html):
-從基本布局延伸-
{%擴展了base.html % }
{%阻止內容%}
h1登錄/h1
表單操作=方法=帖子名稱=登錄
{ { form . hidden _ tag()} }
p
請輸入您的OpenID:br
{ { form . OpenID(size = 80)} } br
/p
p{{form.remember_me}}記住我/p
pin輸入類型=提交值=登錄/p
/表單
{% endblock %}
請問在這個模板中,我們又壹次使用了模板繼承的模式。使用extends語句從base.html繼承模板內容。我們將在以後創建的模板中繼續使用這種方法,這樣我們所有的頁面布局都可以保持壹致。
這個登錄模板明顯不同於普通的HTML表單。它使用模板參數{{...}}來實例化表單字段,該字段來自我們剛剛定義的表單類,模板參數中使用了名稱form。當我們使用view函數引用form類並將其呈現給模板時,我們應該特別註意將form類傳遞給模板的變量名。
我們在配置中打開了CSRF(跨站偽造請求)功能,模板參數{ { form . hidden _ tag()} }將被壹個具有防止CSRF功能的隱藏表單字段替換。打開CSRF函數後,需要將此模板參數添加到所有模板表單中。
我們定義的表單對象中的字段也可以由模板呈現。只需在模板的適當位置添加類似{{ form.field_name }}的模板參數,相關字段就會出現在定義的位置。還有壹些字段可以傳遞參數,例如這個openid字段,因此我們添加了壹個參數以將顯示寬度增加到80個字符。
因為我們沒有在表單中定義壹個具有提交功能的按鈕,所以我們在這裏只能以普通表單字段的方式來實現。但它只是壹個按鈕,與表單中的任何數據都無關,確實沒有必要在form類中定義它。
表單視圖
在見證奇跡的最後壹步中,我們將編寫壹個視圖函數,將登錄表單對象呈現到模板中。
這個函數非常簡單和枯燥,因為我們只需要將表單對象傳遞給模板。以下是我們的視圖函數(fileapp/views.py)的完整內容:
11
12
從燒瓶導入渲染模板,刷新,重定向
從應用導入應用
從表單導入LoginForm
#為簡潔起見,索引視圖函數被取消
@ app . route(/log in,methods =【GET,POST】)
def登錄():
form = LoginForm()
返回render _ template(log in . html,
title =登錄,
表單=表單)
我們引入login form類,然後將其實例化為壹個變量,最後將該變量傳遞給模板。這就是呈現表單字段所要做的全部工作。
上面的代碼還引入了兩個新對象:falsh和redirect,稍後將使用它們。
我做的另壹件事是向路由裝飾器添加壹個新方法。讓Flask知道我們的視圖函數支持GET和POST請求。否則,該視圖函數將只響應GET請求。我們需要獲取用戶在填寫表單後提交的數據,這些數據是從POST請求傳遞過來的。
您可以通過在瀏覽器中測試該程序來理解上述內容。根據與視圖功能相關聯的路線,您應該在瀏覽器中輸入它。
由於我們還沒有編寫任何代碼來接收數據,因此如果您現在單擊頁面上的submit按鈕,它將不會產生任何影響。
從表單接收數據
此外,值得壹提的是,Flask-WTF對表單提交數據的處理使我們接下來的工作變得簡單。以下是我們的登錄視圖功能的新版本,增加了表單數據驗證和處理(fileapp/views.py):
七
八
九
@ app . route(/log in,methods =【GET,POST】)
def登錄():
form = LoginForm()
if form.validate_on_submit():
flash(請求登錄OpenID= + form.openid.data +,remember _ me =+str(form . remember _ me . data))
返回重定向(/index)
返回render _ template(log in . html,
title =登錄,
表單=表單)
validate_on_submit()方法完成表單處理的所有工作。如果在表單向用戶提供數據時調用此方法(例如,chestnut:用戶在它之前修改了提交的數據),它將返回False。當這種情況發生時,妳知道。不明白?也就是說,提交的數據驗證失敗,因此您應該繼續呈現模板。
在提交請求時調用表單的validate_on_submit()方法後,它將從請求中獲取所有提交的數據,然後使用表單字段中綁定的驗證函數進行數據驗證。當所有數據都得到驗證時,它將返回True。這意味著您可以安全地使用這些表單數據。
只要壹個字段驗證失敗,它就會返回False。這時,我們需要將數據返回給用戶,並讓他們更正錯誤的數據。接下來,我們將了解如何在數據驗證失敗時向用戶顯示錯誤消息。
當validate_on_submit()方法返回True時,我們的視圖函數將調用兩個新函數。它們都是從Flask導入的,flash函數用於在下壹個打開的頁面中顯示定義的消息。我們現在用它來調試。因為我們還沒有制作用戶登錄模塊,所以我們只需要顯示用戶提交的數據。Flash功能非常有用,例如為用戶的某些操作提供消息反饋。
flash功能提供的消息不會自動出現在我們的網站頁面上,因此我們需要做壹些事情使其出現在頁面上。為了使我們所有的頁面都具有這壹令人興奮的功能,讓我們將其添加到基本模板中。以下是更新後的基本模板(fileapp/templates/base.html):
超文本標記語言
頭
{% if title %}
標題{{title}} -微博/標題
{% else %}
標題微博/標題
{% endif %}
/頭
身體
div微博:a href=/indexHome/a/div
人力資源
{ % with messages = get _ flash _ messages()% }
{% if messages %}
保險商實驗所
{ % for messages % }中的郵件
li{{ message }} /li
{% endfor %}
/ul
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
/body
/html
我希望妳能理解在模板中顯示flash消息的功能。
我們在視圖函數中使用的另壹個新函數是重定向。該功能將通知用戶的瀏覽器跳轉到指定的地址。在我們的視圖函數中,我們使用它跳轉到主頁。請註意,flash函數傳遞的消息也將在跳轉後顯示在頁面上。
激動人心的時刻到了。運行我們的程序,看看表單是如何工作的。不要填寫表單中的openid字段,看看所需的驗證函數如何發揮其威力來阻止來自千裏之外的所有空數據請求。
改進現場驗證。
我們的程序目前狀態良好,不合格數據的提交將被阻止,並將表單返回供用戶修改,基本符合我們的要求。
但是好像少了點什麽。如果我們在用戶提交數據失敗後給他們壹個提示,讓他們知道是什麽原因造成的,這不是很好嗎?幸運的是,Flask-WTF可以輕松解決這個問題。
當表單域驗證失敗時,Flask-WTF將向表單對象添加壹條錯誤消息。這些消息也可以在模板中使用,所以我們只需要在模板中添加壹點東西。
這是我們添加了驗證消息的登錄模板(fileapp/templates/login.html):
16
17
18
!-擴展基本布局-
{%擴展了base.html % }
{%阻止內容%}
h1登錄/h1
表單操作=方法=帖子名稱=登錄
{ { form . hidden _ tag()} }
p
請輸入您的OpenID:br
{ { form . OpenID(size = 80)} } br
{ % for form . errors . OpenID % }中的錯誤
span style=color:紅色;【{ { error } }】/span
{% endfor %}br
/p
p{{form.remember_me}}記住我/p
pin輸入類型=提交值=登錄/p
/表單
{% endblock %}
我們只在openid字段的右側添加了壹個循環語句,它將顯示openid字段未能驗證的所有消息。無論您的表單有多少個字段,所有未能驗證表單字段的錯誤消息都可以在form.errors .字段名中使用。在這個表單中,我們的表單是form.errors.openid為了使錯誤消息引起用戶的註意,我們還添加了壹個css樣式,該樣式將消息顯示為紅色。
處理OpenID登錄
在現實生活中,我們發現許多人不知道他們有壹些公共帳戶。壹些知名網站或服務提供商將為其成員提供公共帳戶的身份驗證。例如,如果妳有壹個谷歌賬戶,妳實際上有壹個公共賬戶,還有雅虎、美國在線、Flickr等。
為了方便我們的用戶簡單地使用他們的公共帳戶,我們將把這些公共帳戶的鏈接添加到壹個列表中,這樣用戶就不必手動輸入它們。
我們需要將提供給用戶的壹些公共帳戶服務提供商定義到壹個列表中,並將該列表放在配置文件(fileconfig.py)中:
七
八
九
CSRF已啟用=真
SECRET_KEY =妳永遠猜不到
OPENID_PROVIDERS =【
{名稱:谷歌,網址:
{名稱:雅虎,網址:
{名稱:美國在線,網址:
{名稱:Flickr,url:
{名稱:MyOpenID,url:
}]
下壹步是在我們的登錄視圖功能中使用該列表:
@ app . route(/log in,methods =【GET,POST】)
def登錄():
form = LoginForm()
if form.validate_on_submit():
flash(請求登錄OpenID= + form.openid.data +,remember _ me =+str(form . remember _ me . data))
返回重定向(/index)
返回render _ template(log in . html,
title =登錄,
形式=形式,
PROVIDERS = app . config【OPENID _ PROVIDERS】)
我們從app.config導入公共帳戶服務提供商的配置列表,然後通過render_template函數將其作為參數導入到模板中。
我想妳能猜到下壹步該做什麽。我們需要在登錄模板中顯示這些服務提供商鏈接。
24
25
26
27
28
29
30
31
32
33
34
!-擴展基本布局-
{%擴展了base.html % }
{%阻止內容%}
腳本類型=文本/javascript
函數set _ OpenID(OpenID,pr)
{
u = openid.search(用戶名)
如果(u!= -1) {
// openid需要用戶名
用戶=提示(輸入您的
+ pr +
用戶名:)
OpenID = OpenID . substr(0,u)+用戶
}
form = document.forms【登錄】;
form . elements【OpenID】value = openid
}
/腳本
h1登錄/h1
表單操作=方法=帖子名稱=登錄
{ { form . hidden _ tag()} }
p
請輸入您的OpenID,或從下面選擇壹個提供商:br
{ { form . OpenID(size = 80)} }
{ % for form . errors . OpenID % }中的錯誤
span style=color:紅色;【{ { error } }】/span
{% endfor %}br
|{% for pr in providers %}
a href = JavaScript:set _ OpenID({ { pr . URL } },{ { pr . name } });{{pr.name}}/a |
{% endfor %}
/p
p{{form.remember_me}}記住我/p
pin輸入類型=提交值=登錄/p
/表單
{% endblock %}
這個模板似乎增加了壹些東西。壹些公共帳戶需要提供用戶名,我們使用javascript來解決這個問題。當用戶點擊相關的公共帳戶鏈接時,需要用戶名的公共帳戶會提示用戶輸入用戶名,javascript會將用戶名處理為可用的公共帳戶,最後將其插入到openid字段的文本框中。
以下是點擊登錄頁面上的google鏈接後顯示的屏幕截圖: