這裏有兩種可以使用 BluePrint 的方法
- Folder as working URI 使用文件夾作爲一個對應的 URI 的訪問路徑。http://test.com/api 中 api 對應項目中的一個文件夾
- File as working URI 使用文件作爲一個對應的URI 訪問路徑。http://test.com/api 中 api 對應項目中的一個文件.py
Case 1- Folder as working URI
當前目錄文件
./app
├── main (主體模塊:主要定義 uri 和 邏輯的 blueprint py 文件)
│ ├── main.py
├── static(靜態文件目錄:css)
├── templates(模版文件目錄:通用 html )
├── app.py
建立 blueprint 的步驟
- 創建一個藍圖的包,其實已經創建了 爲main, 作爲主要的Web 業務的包,建立藍圖對象 __init__.py
from flask import Blueprint
main = Blueprint('main',__name__)
- 建立一個 views.py 用來保存藍圖使用的視圖view
from . import main
@main.route('/')
def home():
return 'index.html'
- 在 __init__.py 中引入,新建的 views.py
from flask import Blueprint
main = Blueprint('main',__name__)
from . import views
- 在主應用 main.py 文件中的 main 對象上註冊這個main blueprint 對象
from main import main
app.register_blueprint(blueprint=main,url_prefix='/main')
現在的app.py 如下
# /app/app.py
from flask import Flask, Response
import os
# 用戶應用的 目錄
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
from main.main import app_test
app = Flask(__name__)
@app.route('/')
def index():
return Response('<h1>hello world. Will be replaced by Home</h1>')
# register blueprint , set url prefix
app.register_blueprint(blueprint=app_test, url_prefix='/api')
from main import main
app.register_blueprint(blueprint=main,url_prefix='/main')
if __name__=='__main__':
app.run(debug=True)
Debug
上面的代碼在啓動的時候會報錯:
AttributeError: module 'main.main' has no attribute 'name'
當我們點擊進入查看源碼的時候,Code 如下
if blueprint.name in self.blueprints:
assert self.blueprints[blueprint.name] is blueprint, (
"A name collision occurred between blueprints %r and %r. Both"
' share the same name "%s". Blueprints that are created on the'
" fly need unique names."
% (blueprint, self.blueprints[blueprint.name], blueprint.name)
)
這就是一個Name Collision 的問題
使用了 app/main/__init__.py 和 /app/main.main.py 兩個都標識了自己是 main
爲了能繼續使用當前的例子,註釋掉 main.py
新的目錄結構如下
./app
├── main (主體模塊:主要定義 uri 和 邏輯的 blueprint py 文件)
│ ├── main.py.bak
│ ├── __init__.py
│ ├── views.py
├── static(靜態文件目錄:css)
├── templates(模版文件目錄:通用 html )
├── app.py
修改一下 app/app.py ,把有 conflict 的地方都註釋掉
# /app/app.py
from flask import Flask, Response
import os
# 用戶應用的 目錄
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# from main.main import app_test # conflict
app = Flask(__name__)
@app.route('/')
def index():
return Response('<h1>hello world. Will be replaced by Home</h1>')
# register blueprint , set url prefix
# app.register_blueprint(blueprint=app_test, url_prefix='/api') # conflict
from main import main
app.register_blueprint(blueprint=main,url_prefix='/main')
if __name__=='__main__':
app.run(debug=True)
程序跑起來咯
運行機制[^1]
- BluePrint 保存了一組將來可以在應用對象上執行的操作,註冊路由 Route 就是一種路徑操作
- 當在app對象上調用 route 裝飾器註冊路由時,這個操作將修改對象的 url_map 路由表
- 然而,藍圖對象根本沒有路由表,當我們在藍圖對象上調用route裝飾器註冊路由時,它只是在內部的一個延遲操作記錄列表defered_functions中添加了一個項 (博主不懂,無腦掠過)
- 當執行app對象的 register_blueprint() 方法時,應用對象將從藍圖對象的 defered_functions 列表中取出每一項,並以自身作爲參數執行該匿名函數,即調用應用對象的 add_url_rule() 方法,這將真正的修改應用對象的usr_map路由表 (博主不懂,無腦掠過)
FROM:Flask-藍圖(blueprint)
Case 2 - File as working URI
在main 文件夾中加入2個新的文件 product 和 order
./app
├── main (主體模塊:主要定義 uri 和 邏輯的 blueprint py 文件)
│ ├── main.py.bak
│ ├── __init__.py
│ ├── views.py
│ ├── login.py
│ ├── order.py
├── static(靜態文件目錄:css)
├── templates(模版文件目錄:通用 html )
├── app.py
# /app/main/login.py
__author__ = '[email protected]'
from flask import Blueprint,render_template
login = Blueprint('login',__name__)
@login.route('/')
def show():
# return 'Login'
return render_template('login.html') # add the html pages under templates
# /app/main/order.py
__author__ = '[email protected]'
from flask import Blueprint
'''
創建一個blueprint對象。第一個參數可看做該blueprint對象的姓名
在一個app裏,姓名不能與其餘的Blueprint對象姓名重複
第二個參數__name__用作初始化
'''
order = Blueprint('order',__name__)
@order.route('/') #將藍圖對象當做'app'那樣使用
def login():
return 'Order'
修改一下 app/app.py ,加入新的blueprint
# /app/app.py
from flask import Flask, Response
import os
# 用戶應用的 目錄
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
# from main.main import app_test # conflict
app = Flask(__name__)
@app.route('/')
def index():
return Response('<h1>hello world. Will be replaced by Home</h1>')
# register blueprint , set url prefix
# app.register_blueprint(blueprint=app_test, url_prefix='/api') # conflict
from main import main
app.register_blueprint(blueprint=main,url_prefix='/main')
from main.login import login
app.register_blueprint(blueprint=login,url_prefix='/login') # 將 main 模塊裏的藍圖對象account註冊到app
from main.order import order
app.register_blueprint(blueprint=order,url_prefix='/order') # 將 main 模塊裏的藍圖對象order註冊到app
if __name__=='__main__':
app.run(debug=True)
測試通過
運行機制
- app.py 文件運行,首先運行目錄下面的 __init__.py 文件中的代碼 (博主case2例子中沒有使用)
- __init__ 文件導入Flask 以及 main 目錄下面的py文件
- 接着 __init__ 或者 app 創建Flask對象
- 將 main 目錄下面的模塊文件註冊到藍圖對象中
- app.py 最終運行的就是 __init__.py 和 app.py 中的代碼 app 對象