Blueprint (藍(lán)圖)
Blueprints are the recommended way to implement larger or more
pluggable applications in Flask 0.7 and later.
Blueprint 是為了更方便實(shí)現(xiàn)模塊化開發(fā)而誕生的.
模塊化
為什么要模塊化?
在一個py 文件中寫成百上千或者更多個接口, 相信大部分或者絕大部分人都不愿意維護(hù)這樣的代碼, 其次所有接口都寫在一個文件中不利于團(tuán)隊(duì)協(xié)作. 基于以上兩點(diǎn),分模塊 / 團(tuán)隊(duì)協(xié)作 的模塊化就顯的很有必要了.
Blueprint 與模塊
一般來說,都會以功能進(jìn)行模塊劃分, 這里就不討論如何劃分了. 假設(shè)有首頁 / 新聞頁 / 登錄 三個模塊.
原始寫法
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'index'
@app.route('/news')
def index():
return 'index'
@app.route('/login')
def index():
return 'index'
if __name__ == '__main__':
app.run(debug=True)
接口通過app.route 將規(guī)則 和 視圖函數(shù)進(jìn)行綁定, 存在同名函數(shù),綁定失敗
**導(dǎo)入Blueprint **
# 導(dǎo)入Blueprint
from flask import Blueprint
from flask import Flask
# 實(shí)例化Blueprint 對象
# 藍(lán)圖名, import_name ,規(guī)則前綴
index_blue = Blueprint("index", __name__, url_prefix="/index")
news_blue = Blueprint("news", __name__, url_prefix="/news")
login_blue = Blueprint("login", __name__, url_prefix="/login")
app = Flask(__name__)
# 用Blueprint 對象實(shí)現(xiàn)接口
@index_blue.route('/')
def index():
return 'index'
@news_blue.route('/')
def index():
return 'news'
@login_blue.route('/')
def index():
return 'index'
# 注冊Blueprint
app.register_blueprint(index_blue)
app.register_blueprint(news_blue)
app.register_blueprint(login_blue)
if __name__ == '__main__':
print(app.url_map)
app.run(debug=True)
運(yùn)行結(jié)果
Map([<Rule '/index/' (HEAD, GET, OPTIONS) -> index.index>,
<Rule '/login/' (HEAD, GET, OPTIONS) -> login.index>,
<Rule '/news/' (HEAD, GET, OPTIONS) -> news.index>,
<Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])
Blueprint 的使用步驟
- 實(shí)例化Blueprint 對象, 需要導(dǎo)入Blueprint 類
- 用Blueprint 對象實(shí)現(xiàn)實(shí)現(xiàn)接口
- 注冊Blueprint
雖然用Blueprint 實(shí)現(xiàn)了接口,但是接口依然在一個文件中, 接下來進(jìn)行拆分
模塊化

main.py
from flask import Flask
from modules import index_blue, news_blue, login_blue
app = Flask(__name__)
# 注冊藍(lán)圖
app.register_blueprint(index_blue)
app.register_blueprint(news_blue)
app.register_blueprint(login_blue)
if __name__ == '__main__':
print(app.url_map)
app.run(debug=True)
__init__.py
# 導(dǎo)入Blueprint
from flask import Blueprint
# 實(shí)例化藍(lán)圖對象
index_blue = Blueprint("index", __name__, url_prefix="/index")
news_blue = Blueprint("news", __name__, url_prefix="/news")
login_blue = Blueprint("login", __name__, url_prefix="/login")
from . import index
from . import news
from . import login
index.py
from . import index_blue
@index_blue.route('/')
def index():
return 'index'
login.py
from . import login_blue
@login_blue.route('/')
def index():
return 'login'
news.py
from . import news_blue
@news_blue.route('/')
def index():
return 'news'
運(yùn)行結(jié)果
Map([<Rule '/index/' (HEAD, GET, OPTIONS) -> index.index>,
<Rule '/login/' (HEAD, GET, OPTIONS) -> login.index>,
<Rule '/news/' (HEAD, GET, OPTIONS) -> news.index>,
<Rule '/static/<filename>' (HEAD, GET, OPTIONS) -> static>])
藍(lán)圖的作用原理
猜測: 未使用藍(lán)圖時, url_map 存放的是形如 <Rule '/index/' (HEAD, GET, OPTIONS) -> index> 這樣的Rule 對象使用藍(lán)圖之后,url_map 存放的是形如 <Rule '/index/' (HEAD, GET, OPTIONS) -> index.index> 這樣的Rule 對象.
所以藍(lán)圖是通過改變視圖函數(shù)的端點(diǎn)的方式區(qū)分視圖函數(shù)的.
endpoint
在flask初探二 中簡單的探究了endpoint, 這里將探究藍(lán)圖與endpoint 之間的關(guān)系
藍(lán)圖的route
def route(self, rule, **options):
"""Like :meth:`Flask.route` but for a blueprint. The endpoint for the
:func:`url_for` function is prefixed with the name of the blueprint.
"""
def decorator(f):
endpoint = options.pop("endpoint", f.__name__)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
和 flask 的route 基本一樣
藍(lán)圖的add_url_rule
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
"""Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for
the :func:`url_for` function is prefixed with the name of the blueprint.
"""
if endpoint:
assert '.' not in endpoint, "Blueprint endpoint's should not contain dot's"
self.record(lambda s:
s.add_url_rule(rule, endpoint, view_func, **options))
BlueprintSetupState 的add_url_rule
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
"""A helper method to register a rule (and optionally a view function)
to the application. The endpoint is automatically prefixed with the
blueprint's name.
"""
if self.url_prefix:
rule = self.url_prefix + rule
options.setdefault('subdomain', self.subdomain)
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
defaults = self.url_defaults
if 'defaults' in options:
defaults = dict(defaults, **options.pop('defaults'))
# 重點(diǎn)在這
self.app.add_url_rule(rule, '%s.%s' % (self.blueprint.name, endpoint),
view_func, defaults=defaults, **options)
循著源碼的運(yùn)行,可以看到藍(lán)圖最終是通過調(diào)用 app.add_url_rule 的方式將規(guī)則和視圖函數(shù)進(jìn)行的綁定, 區(qū)別是在調(diào)用的時候?qū)ndpoint 進(jìn)行的傳值, 從而印證了我們開始的猜測.
結(jié)論
- 藍(lán)圖是通過改變endpoint 的方式區(qū)分視圖函數(shù)的.
- endpoint 默認(rèn)情況下是視圖函數(shù)名,
- 使用藍(lán)圖后, endpoint 為 藍(lán)圖名.視圖函數(shù)名
endpoint 與 url_for
url_for
def url_for(endpoint, **values):
...(省略)...
從url_for 方法的定義可以看出, url_for需要的是endpoint
- 在不使用藍(lán)圖的情況下, 可以直接使用函數(shù)名字符串得到URL
@app.route("/")
def index():
pass
url_for("index")
- 使用藍(lán)圖時, 使用 藍(lán)圖名.視圖函數(shù)名 字符串得到URL
login_blue = Blueprint("login", __name__, url_prefix="/login")
@login_blue.route('/')
def index():
return 'login'
url_for("login.index") # 得到 /login/
到此結(jié)? DragonFangQy 2018.6.30