Flask Web Development —— Web表單(下)

四、視圖函數中的表單操做

在新版本的hello.py中,index()視圖函數渲染表單並接收其數據。示例4-4展現更新後的index()視圖函數。html

示例4-4. hello.py:路由方法git

@app.route('/', methods=['GET', 'POST']) 
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data
        form.name.data = ''
    return render_template('index.html', form=form, name=name)

methods參數被添加到app.route裝飾器中,目的是讓Flask註冊視圖函數爲GETPOST請求處理程序到URL映射中。若methods參數未給出,視圖函數將只註冊爲GET請求。github

添加POST到方法列表中是有必要的,由於表單提交使用POST請求操做會更方便。使用GET請求提交表單也行,只是GET請求沒有body部分,數據是追加到URL上做爲返回字符串且能夠在瀏覽器的地址欄中看到。因爲這個和其餘一些緣由,表單提交一般使用POST請求。web

局部變量name用於保存從表單中接收到的名字,初始化時變量爲None。視圖函數建立一個NameForm實例來表示一個表單。表單的validate_on_submit()方法會在表單被提交且數據經過了全部驗證的時候返回True。其餘狀況下validate_on_submit()返回False。該方法的返回值有效的決定了表單是須要渲染仍是其餘處理。數據庫

當用戶第一次訪問應用程序,服務器會收到一個沒有表單數據的GET請求,這個時候validate_on_submit()會返回Falseif語句中的代碼將被略過直接進行渲染模板處理,這個時候render_template()函數將獲取表單對象和已經被設置爲Nonename變量做爲參數。用戶則能夠在瀏覽器上看到表單的顯示。flask

當用戶提交表單,服務器會收到一個帶有數據的POST請求。validate_on_submit()調用Required()驗證程序驗證相應的表單域。若是name不爲空,驗證程序接收它同時validate_on_submit()返回True。如今用戶輸入的名字已是做爲表單域可訪問的數據屬性。在if語句中,這個名字被賦值給局部變量name且表單域的數據屬性經過賦值爲空字符串而被清除。調用最後一行的render_template()來渲染模板,可是此次name參數包含了來自表單的名字,因此能夠看到一個個性化的打招呼頁面。瀏覽器

建議:若是你有克隆在GitHub上的應用程序,你如今能夠運行git checkout 4a來切換到這個版本的應用程序。服務器

圖像4-1展現用戶初次進入網站在瀏覽器窗口看到的表單是怎樣的。當用戶提交名字,應用程序收到一個個性化的打招呼響應。下面的表單仍然出現,因此只要願意用戶能夠提交一個新的名字。圖像4-2展現用戶輸入名字後的狀態。cookie

圖像4-1. Flask-WTF的web表單session

若是用戶提交一個空名字的表單,Required()驗證程序捕捉到錯誤,就像圖像4-3那樣。注意這些功能都是自動提供的。這是一個很好的例子,精心設計的Flask-WTF和Flask-Bootstrap擴展能讓您的應用程序更強大。

圖像4-2. 提交後的web表單

圖像4-3. 驗證錯誤後的web表單

五、重定向和用戶sessions

上個版本的hello.py有個問題。若是你輸入你的名字並提交它,而後單擊瀏覽器中刷新按鈕,你將獲得一個警告要求再次確認以前提交的表單。由於請求刷新頁面的時候瀏覽器重複了上一次發送的請求。當上一次發送的是一個帶有表單數據的POST請求,刷新頁面會致使重複的表單提交,事實上這些並非咱們想看到的。

許多用戶不能理解來自瀏覽器的這些警告。出於這個緣由,對web應用程序來講,一種不錯的方法是永遠不將POST請求做爲瀏覽器最後發送的請求。

這個方法可使用redirect響應POST請求來代替常規的響應來實現。重定向是一個特殊類型的響應,使用URL來代替HTML代碼字符串。當瀏覽器收到這個響應,它就會給重定向URL發出一個GET請求,而後顯示頁面。頁面也許須要幾毫秒的時間來加載,由於須要發送第二個請求給服務器,除此以外用戶不會看到任何不一樣。如今最後一次請求爲GET,因此刷新會像預期的那樣。這個方法被稱爲Post/Redirect/Get模式

可是這個方法帶來了第二個問題。當應用程序處理POST請求,須要訪問用戶輸入並保存在form.name.data中的名字,可是一旦該請求結束表單數據就會丟失。由於POST請求是經過重定向來處理,應用程序須要存儲名字,以便重定向後的請求能夠獲得它並使用它來建立真實的響應。

應用程序能夠「記住」一些變量從一個請求到另外一個請求經過將變量保存到用戶會話中,對於每個鏈接過來的客戶端它都是一個私有存儲區域。做爲一個與請求上下文關聯的變量之一,用戶會話已經在第二章中介紹過了。它被稱爲會話並能夠像Python標準字典那樣訪問。

注:默認狀況下,用戶會話被存放於客戶端的cookies,使用配置的SECRET_KEY來加密簽名。任何篡改cookie內容將會使簽名無效,從而使會話失效。

示例4-5展現實現重定向和用戶會話的index()視圖函數。

示例4-5. hello.py:重定向和用戶會話

from flask import Flask, render_template, session, redirect, url_for

@app.route('/', methods=['GET', 'POST']) 
def index():
    form = NameForm()
    if form.validate_on_submit():
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html', form=form, name=session.get('name'))

在上一個版本中,局部變量name用於保存用戶在表單中輸入的姓名。這個變量位於用戶會話中的session['name']中,所以能夠保存很長時間。

如今請求來自表單的合法數據都會以redirect()調用來結束,生成HTTP重定向響應。redirect()函數把URL做爲重定向的參數。這個例子中使用的重定向URL是一個根URL,因此響應能夠寫成redirect('/')這樣簡潔,可是咱們一般使用Flask的URL生成器函數url_for()來代替。咱們鼓勵使用url_for()函數來生成URLs,由於該函數使用URL映射來生成URLs,因此生成的URLs保證與定義的路由兼容,而且使用這個函數任何路由名發生變化都會自動變得有效,路由功能不受影響。

url_for()惟一必須的參數就是endpoint名,也是每一個路由的內部名。默認狀況下,路由的endpoint是一個附加到視圖函數的名稱。在這個示例中,處理根URL的視圖函數爲index(),因此給url_for()的名稱爲index。

最後一個改動是在render_template()函數中,使用session.get('name')從會話中獲取name參數。和使用普通字典同樣,使用get()去請求字典key來避免發生找不到key異常,由於對於沒有的keyget()返回默認值None

建議:若是你有克隆在GitHub上的應用程序,你如今能夠運行git checkout 4b來切換到這個版本的應用程序。

這個版本的應用程序,你能夠在你的瀏覽器中刷新頁面看到你預期的行爲。

六、消息提示

有時候在請求完成後給用戶一個提示消息是很是有用的。能夠是一個確認消息、警告消息或錯誤消息。典型的示例就是當你在網站提交登陸表單出現錯誤的時候服務器響應渲染登陸表單並伴隨一條消息,告知你的用戶名或密碼無效。

做爲核心特性Flask具備這樣的功能。示例4-6展現如何使用flash()函數來實現這一目的。

示例4-6. hello.py:消息提示

from flask import Flask, render_template, session, redirect, url_for, flash

@app.route('/', methods=['GET', 'POST']) 
def index():
    form = NameForm()
    if form.validate_on_submit():
        old_name = session.get('name')
        if old_name is not None and old_name != form.name.data:
            flash('Looks like you have changed your name!') 
        session['name'] = form.name.data
        form.name.data = ''
        return redirect(url_for('index'))
    return render_template('index.html',
        form = form, name = session.get('name'))

在這個示例中,每次提交一個名字都會和用戶會話中保存的名字進行比較。若是兩個名字不同,flash()函數會被調用,消息會在下一次發回客戶端的響應中顯示。

調用flash()還不能獲取並顯示消息;應用程序使用的模板須要渲染這些消息。渲染消息最好的地方是在基礎模板中,由於這可使得全部頁面均可以使用這些消息。Flask提供get_flashed_messages()函數給模板去接收消息並渲染它們,就像4-7展現的那樣。

示例4-7. templates/base.html:消息渲染

{% block content %}


<div class="container">
  {% for message in get_flashed_messages() %} 
  <div class="alert alert-warning">
    <button type="button" class="close" data-dismiss="alert">&times;</button>
    {{ message }}
  </div>
  {% endfor %}

  {% block page_content %}{% endblock %}
</div>


{% endblock %}

在這個示例中,使用Bootstrap的警告CSS樣式作警告消息渲染(展現在圖像4-4中就是之一)。

圖像4-4. 消息提示

這裏須要使用循環由於可能會有多個消息排隊顯示,在前面的請求週期中每次都會調用flash()

get_flashed_messages()中檢索到的消息在下次調用這個函數時是不會返回的。因此消息只顯示一次而後丟棄。

建議:若是你有克隆在GitHub上的應用程序,你如今能夠運行git checkout 4c來切換到這個版本的應用程序。

可以接收用戶經過web表單發送的數據是大多數應用程序的基本功能,一樣將數據到永久存儲到媒介上也是必須的。下一章的主題是Flask和數據庫的使用。

相關文章
相關標籤/搜索