1. 程式人生 > 實用技巧 >flask元件化開發:藍圖

flask元件化開發:藍圖

Flask 藍圖介紹

藍圖也就是BluePrint是 Flask 提供的一個類,它具備 Flask 核心物件的很多功能,其中最重要的就是註冊路由,我們通過藍圖,可以將檢視函式根據不同的功能拆分到不同的模組中,從而實現對檢視函式的模組化管理與開發。

簡單來說,我們可以把藍圖認為是一個完整 Web 應用的一部分,以個人Blog為例,它可以有Blog的展示部分,也需要有後臺部分,此外還有登陸的部分,這些不同的部分就可以通過藍圖來進行拆分管理,它們組合起來就是一個完整的 Web 應用。

建立藍圖

先不忙建立藍圖,既然藍圖的作用是分模組存放檢視函式,那麼我們肯定需要建立 Python 模組以及 Python 包,本文所用的示例結構是如下這樣的:

. ├── demo # 應用包 │ ├── __init__.py │ └── blueprints # 藍圖包 │ ├── home.py # 首頁藍圖模組 │ ├── admin.py # 後臺藍圖模組 │ └── __init__.py └── app.py # 入口檔案

接下來,就可以建立藍圖了,在home.py中增加如下程式碼:

# demo/blueprints/home.py from flask import Blueprint home = Blueprint("home", __name__, url_prefix="/home")
@home.route('/') def index(): return "This is home index page."

上面的程式碼中,我們首先例項化了一個Blueprint物件,和例項 Flask 核心物件不同,Blueprint多了兩個額外的引數:

  • "home": 藍圖的名稱,這是一個必須的引數,之前在Flask 路由與檢視函式一文的路由機制中,我專門談到了 Flask 中endpoint端點的作用,這裡的藍圖名稱就是構成檢視函式endpoint的一部分。
  • url_prefix="/home": 該藍圖下所有路由的字首地址,比如這裡定義的字首是/home,那麼如果這個藍圖下有一個/hello
    路由,那麼它的完整 URL 地址就是這樣的127.0.0.1:5000/home/hello,這裡要注意的是,url_prefix並非是必須的引數,我們也可以在註冊藍圖的時候定義字首地址,後面會提到。

除了上面這些,藍圖在註冊路由方面和 Flask 核心物件是一模一樣的,因為藍圖在註冊路由的時候呼叫的也是add_url_rule這個方法,只不過此時這個方法並不是來自 Flask 核心物件了。

註冊藍圖

註冊藍圖就比較簡單了,在app.py中,新增如下程式碼:

# app.py from flask import Flask from demo.blueprints.home import home app = Flask(__name__) # 註冊藍圖 app.register_blueprint(home)

註冊藍圖只需要呼叫 Flask 核心物件的register_blueprint方法即可。

接著我們就可以測試一下效果了,在命令列啟動 Flask 服務:

$ export FLASK_APP=app.py $ export FLASK_ENV=development $ flask run

訪問http://127.0.0.1:5000/home/可以看到如下頁面:

註冊藍圖時設定 URL 字首

前面建立藍圖的時候,url_prefix是定義在了例項化Blueprint的時候,除了這種方式,我們還可以在註冊藍圖的時候定義url_prefix,首先把例項化藍圖時定義的url_prefix刪除掉:

... # 刪除 url_prefix home = Blueprint("home", __name__) ...

接著在註冊藍圖的時候,新增url_prefix引數

... # 註冊藍圖時設定 url_prefix 引數 app.register_blueprint(home, url_prefix="/home") ...

不管是在註冊藍圖的時候設定url_prefix還是在例項化藍圖的時候設定,這兩種方式的結果都是一樣的,在編寫程式碼的時候選擇其中一種即可,不過如果藍圖特別特別多或者你比較習慣 Django 那種路由管理模式那麼在註冊藍圖的時候設定url_prefix是個好選擇,畢竟如果藍圖多了的話修改某些藍圖的 URL 字首肯定是在一個統一的地方比較方便。

endpoint 端點

在繼續接下來的內容之前,我想在這裡演示一下 Flask 對於endpoint的處理。

上面我們已經定義了一個藍圖,並且註冊了一個路由,接下來在admin.py中,我們再定義一個藍圖併為其註冊一個路由。

# demo/blueprints/admin.py from flask import Blueprint admin = Blueprint("admin", __name__, url_prefix="/admin") @admin.route("/") def index(): return "This is admin index page."

然後把這個藍圖註冊給 Flask 核心物件

# app.py from flask import Flask from demo.blueprints.home import home from demo.blueprints.admin import admin app = Flask(__name__) app.register_blueprint(home) app.register_blueprint(admin)

此時就有了兩個藍圖,這兩個藍圖中都有一個檢視函式index,之前在Flask 路由與檢視函式這篇文章中,我就提到 Flask 通過endpoint來指向檢視函式,這種機制是為了避免檢視函式在名稱空間上的衝突,下面到flask shell中,執行如下程式碼:

$ flask shell In [1]: from app import app In [2]: app.url_map Out[2]: Map([<Rule '/admin/' (GET, OPTIONS, HEAD) -> admin.index>, <Rule '/home/' (GET, OPTIONS, HEAD) -> home.index>])

通過url_map屬性可以查詢到當前的 Flask 應用所有的路由地址和其指向的endpoint,在這裡我們可以看到,當前的 Flask 應用一共有兩個 URL :

  • /admin/是 URL 相對路徑。
  • admin.index就是endpoint了。

這裡的重點是 URL 路徑所指向的endpoint,它是由藍圖的名稱和檢視函式名稱共同構成的,如果沒有endpoint當用戶請求http://127.0.0.1:5000/home/或者http://127.0.0.1:5000/admin/的時候,因為存在兩個index檢視函式,直接通過 URL 找檢視函式就出問題了,到底哪個index函式對應的是使用者所請求 URL ?所以 Flask 才需要endpoint這種機制來處理 URL 和檢視函式之間的對映。

藍圖資源

藍圖除了可以將路由模組化,一樣也可以將對應的靜態檔案和模板模組化,在演示藍圖處理自身靜態資源之前,我們還需要對當前的目錄結構做一些改動,將我們之前建立的兩個藍圖模組移動到各自對應的資料夾中,接著在home目錄下建立templatesstatic目錄用來存放該藍圖下的模板檔案和靜態檔案,最後在templates目錄下建立index.html並在static目錄下建立main.css

. ├── demo │ ├── __init__.py │ └── blueprints │ ├── __init__.py │ ├── admin │ │ ├── __init__.py │ │ └── admin.py │ └── home │ ├── __init__.py │ ├── templates # 模板目錄 │ └── home │ └── index.html │ ├── static # 靜態資源目錄 │ │ ├── main.css │ └── home.py └── app.py

接下來,還需要簡單的改動一下app.py中的引用:

# app.py from flask import Flask from demo.blueprints.home.home import home from demo.blueprints.admin.admin import admin ...

最後分別在index.htmlmain.css新增下面的程式碼

<!-- demo/blueprints/home/templates/home/index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>This is home index page.</h1> </body> </html> /* demo/blueprints/home/static/main.css */ h1 { color: orange; font-style: italic; }

做好準備工作,就可以演示藍圖使用自身的模板和靜態檔案了。

藍圖模板

首先看下模板的使用,要想讓藍圖正確的識別到這個模板,首先需要配置藍圖的模板路徑,在例項化藍圖的時候,通過template_folder引數指定模板路徑:

from flask import Blueprint, render_template # 新增 template_folder 引數指定模板路徑 home = Blueprint("home", __name__, url_prefix="/home", template_folder="templates") @home.route('/') def index(): return render_template("home/index.html")

上述程式碼中,指定的模板路徑是一個相對路徑,這個路徑是基於藍圖例項根目錄的;此外在建立模板目錄的時候,我特地在templates目錄下多建立了一個home目錄儲存index.html這也是有原因的,如果app.py根目錄下還有一個templates全域性模板目錄,而其中也有一個index.html,那麼此時全域性的index.html的優先順序是高於藍圖模板的優先順序的,所以如果不新增一個home目錄來區分藍圖模板和全域性模板,那麼render_template("index.html")這段程式碼會優先去使用templates下的index.html

當然如果全域性的templates目錄下,也有home目錄,也存在index.html,那麼還是會覆蓋藍圖的templates/home/index.html,所以這裡就引發了是否有必要為藍圖單獨建立模板目錄的問題了,畢竟我們完全可以在全域性templates目錄中,通過資料夾的形式區分模板所屬的藍圖,不過這個問題是仁者見仁的事情,我個人是不傾向於給藍圖單獨指定模板目錄的。

藍圖靜態檔案

演示了藍圖模板,再來看看藍圖的靜態檔案,藍圖獨有的靜態檔案也需要和模板一樣指定靜態檔案目錄的路徑:

... # 新增 static_folder 引數指定靜態檔案路徑 home = Blueprint("home", __name__, url_prefix="/home", template_folder="templates", static_folder="static") ...

通過static_folder即可設定藍圖的靜態檔案路徑,和模板路徑的設定差不多,指定相對路徑即可。

接著,到index.html中,我們需要引用靜態檔案了:

... <head> ... <link rel="stylesheet" href="{{ url_for('home.static', filename='main.css') }}"> </head> ...

和引用全域性靜態檔案不同,引用藍圖獨有的靜態檔案時,我們需要指定藍圖的字首home.static,這樣 Flask 才會正確的前往藍圖的/static下尋找靜態檔案;此外和模板不同的是,藍圖不存在優先順序的問題,指定了字首之後,它就只會在藍圖中搜索靜態檔案。

最後,看一眼網頁,我們單獨為藍圖設定的模板和靜態檔案工作的還是正常的:

轉載:https://www.hizxc.com/1563.html#zhu_ce_lan_tu