flask文件學習筆記1-快速入門

youjia0721發表於2019-02-16

開始決定認真的在網上寫一些東西,主要原因還是在於希望能提升學習效果。雖說python寫了有幾年,但是web後端框架的確沒怎麼接觸過,買了本狗書寥寥草草的過了一遍,發現很多東西還是理解不深,真的是好記性不如爛筆頭,知識也要從基礎開始,退回來好好看看官方文件,再去看狗書吧。
網上有翻譯好的官方文件,基本是基於0.10.1版本翻譯的,和目前版本對比了一下,細節上還是有一些不同(狗書也存在這個問題),所以還是老老實實的看英文原版學習吧,目前的版本是0.12.2

“微型”的含義

眾所周知,flask是一個使用Python開發的“微型”Web框架,文件中特意強調了,所謂“微型”並不意味著Web應用的開發只能寫在一個Python檔案裡,也不意味著flask自身功能不夠豐富。“微型”的目的在於,保持一個“簡單”並且“可擴充套件”的框架核心,為開發者提供一個選擇自由的Web框架。基於此,開發者可以自由的選擇資料庫或模板引擎,為自己的Web應用做合適的選擇。

最小應用

通過flask實現一個Hello World只需要幾行程式碼

from flask import Flask
app = Flask(__name__)

@app.route(`/`)
def hello_world():
    return `Hello, World!`

把一頭大象放進冰箱只需三步:

  1. 引用Flask類,並建立Flask類的例項。這個例項就是HelloWorld應用的WSGI介面。
  2. 編寫hello_world函式,返回`hello, World!`字串訊息。
  3. 使用route裝飾器,為hello_world建立路徑為`/`的路由。

這個示例程式碼與0.10版不同,在舊版文件中,通過在程式碼中新增app.run()方法來執行這個Web應用,而在0.12版文件中,應用的啟動工作使用了命令列的方式來處理:

$ export FLASK_APP=hello.py
$ flask run
 * Running on http://127.0.0.1:5000/

或者:

$ export FLASK_APP=hello.py
$ python -m flask run
 * Running on http://127.0.0.1:5000/

通過給FLASK_APP環境變數賦值,告訴flask它的web應用是哪個。我嘗試了在程式碼中使用app.run()方法啟動,也一樣可以執行。

from flask import Flask

app = Flask(__name__)

@app.route(`/`)
def hello_world():
    return `Hello World!`

if __name__ == `__main__`:
    app.run(`0.0.0.0`)

Debug模式

開啟debug模式可實現程式碼變更的熱載入,即:程式碼修改後,不需要重啟flask server,就可以自動觸發變更程式碼的載入。
另外,開啟debug模式可以實現在頁面檢視執行中的錯誤資訊,追蹤錯誤發生原因,適合開發過程中的錯誤除錯。
開啟Debug模式的方法包括:

$ export FLASK_DEBUG=1
$ flask run

以及在程式碼中,為Flask類例項的run方法中,指明debug引數為True:

app.run(debug=True)

路由

在Flask下,使用者可以使用@app.route()裝飾器為頁面設計具有可讀性的靜態路由,也可以在路由部分中加入變數,以使路由動態可變。
路由的形式類似於linux下的檔案路徑。
示例如下:

#靜態路由
@app.route(`/hello`)
def hello():
    return `Hello, World`
#使用動態變數的路由(未指定變數型別)
@app.route(`/user/<username>`)
def show_user_profile(username):
    # show the user profile for that user
    return `User %s` % username

#使用動態變數的路由(指定變數型別)
@app.route(`/post/<int:post_id>`)
def show_post(post_id):
    # show the post with the given id, the id is an integer
    return `Post %d` % post_id

指定的路由變數,可以作為被裝飾的函式引數傳入進來。當路由尾部加入`/`時,無論在瀏覽器位址列中輸入的網址尾部是否加`/`,瀏覽器都會自動重定向到有/的路由上。

url_for()函式

flask模組提供了url_for()函式用於獲取函式的URL,因此在專案中所有引用到URL字串的地方,都可以使用url_for(func, **kwargs)來獲取函式的URL,這樣做的好處在於,可以使專案更容易維護。當某函式URL發生變更時,只需修改一處地方即可,而無須修改每一處URL引用。個人認為,在開發過程的任何時候,使用硬編碼都是極為不妥的。

HTTP方法

http作為客戶端與服務端的互動協議,包含了不同型別的請求方法(method),Flask中,最長使用的是GET、PUT和POST方法,一條路由適用哪種方法,可以在route裝飾器中定義。如不明確定義,route裝飾器中預設定義為GET方法。
官方例子:

from flask import request

@app.route(`/login`, methods=[`GET`, `POST`])
def login():
    if request.method == `POST`:
        do_the_login()
    else:
        show_the_login_form()

http還包括HEAD以及OPTIONS方法,在較新的Flask中,已經為使用者內部實現,因此一般開發過程中無需在意。

靜態檔案

Flask的靜態檔案目錄預設為專案目錄內的static目錄,一般所有靜態檔案都存放在這個目錄內。

模板渲染

Flask內建了Jinja2作為模板引擎,並提供render_template方法用於模板渲染,使用起來很方便,只需在方法內指定需要渲染的html檔名稱,並傳入模板變數值即可實現模板渲染。
官方示例:

from flask import render_template

@app.route(`/hello/`)
@app.route(`/hello/<name>`)
def hello(name=None):
    return render_template(`hello.html`, name=name)

預設情況下,Flask會到當前專案目錄下的templates目錄內尋找模板檔案。
官方模板檔案示例:

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello, World!</h1>
{% endif %}

模板檔案之間可實現繼承,這一特性保證了不同頁面內的重複頁面元素(頁頭、頁尾、導航欄)等,可通過模板繼承的方式迅速實現。

訪問請求資料

來自客戶端的http請求,在server端以request物件存在。
Flask為每一個request建立一個處理執行緒,並線上程內部建立上下文實現執行緒安全。因此開發者在開發過程中不需要為執行緒安全費太多心思。
關於request物件,獲取客戶端傳輸來的資料方式非常簡單,類似於字典的形式,只需要在request.method中指明key的值即可實現:

#獲取登入表單資料
@app.route(`/login`, methods=[`POST`, `GET`])
def login():
    error = None
    if request.method == `POST`:
        if valid_login(request.form[`username`],
                       request.form[`password`]):
            return log_the_user_in(request.form[`username`])
        else:
            error = `Invalid username/password`
    # the code below is executed if the request method
    # was GET or the credentials were invalid
    return render_template(`login.html`, error=error)

文件在此處還提及了檔案上傳場景以及cookie的簡單用法,後續文件應當有更加詳細的記錄,在此不詳述。

錯誤與重定向

Flask使用redirect()函式處理重定向邏輯。使用abort(error_code)處理錯誤返回。
若希望對錯誤頁面進行定製,可使用errorhandler(error_code)裝飾器修飾對應的檢視函式,定義本地錯誤頁面。

關於應答

flask有自己的應答處理邏輯,可大致總結為:
1.檢視函式返回字串時,flask會自動將返回字串封裝如標準response物件內
2.使用者也可以在檢視函式內使用make_response()函式建立response物件並返回,這樣做的意義是,在返回前使用者可以對response物件的部分內容進行設定,例如cookie。
3.如果返回物件是一個tuple,那麼內容順序格式應滿足(response, status, headers)這樣的格式

會話session

session記錄了客戶端與server之間的一些資訊,官方文件給出了使用者登陸狀態的例子。通過判斷session中是否存在username鍵值來判斷使用者是否已登入,以此為依據返回不同的展示內容。
示例如下:

from flask import Flask, session, redirect, url_for, escape, request

app = Flask(__name__)

@app.route(`/`)
def index():
    if `username` in session:
        return `Logged in as %s` % escape(session[`username`])
    return `You are not logged in`

@app.route(`/login`, methods=[`GET`, `POST`])
def login():
    if request.method == `POST`:
        session[`username`] = request.form[`username`]
        return redirect(url_for(`index`))
    return ```
        <form method="post">
            <p><input type=text name=username>
            <p><input type=submit value=Login>
        </form>
    ```

@app.route(`/logout`)
def logout():
    # remove the username from the session if it`s there
    session.pop(`username`, None)
    return redirect(url_for(`index`))

# set the secret key.  keep this really secret:
app.secret_key = `A0Zr98j/3yX R~XHH!jmN]LWX/,?RT`

使用session的前提是必須設定金鑰,金鑰的獲取可以使用python提供的隨機函式生成。

>>> import os
>>> os.urandom(24)

日誌模組

flask的日誌模組與python的logging模組使用方式類似,應該是做了內部整合,程式碼形式略微不同,在此做記錄:

app.logger.debug(`A value for debugging`)
app.logger.warning(`A warning occurred (%d apples)`, 42)
app.logger.error(`An error occurred`)

相關文章