Python - Flask 無腦學習實踐 (三)Flask Blueprint 使用和運行的簡單說明

這裏有兩種可以使用 BluePrint 的方法
  1. Folder as working URI 使用文件夾作爲一個對應的 URI 的訪問路徑。http://test.com/api 中 api 對應項目中的一個文件夾
  2. 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 的步驟

  1. 創建一個藍圖的包,其實已經創建了 爲main, 作爲主要的Web 業務的包,建立藍圖對象 __init__.py
from flask import Blueprint
main = Blueprint('main',__name__)
  1. 建立一個 views.py 用來保存藍圖使用的視圖view
from . import main

@main.route('/')
def home():
    return 'index.html'
  1. 在 __init__.py 中引入,新建的 views.py
from flask import Blueprint

main = Blueprint('main',__name__)

from . import views
  1. 在主應用 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)

程序跑起來咯
root python Flask 3
main python flask 3

運行機制[^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)

測試通過
order python flask 3
login python flask 3

運行機制

  1. app.py 文件運行,首先運行目錄下面的 __init__.py 文件中的代碼 (博主case2例子中沒有使用)
  2. __init__ 文件導入Flask 以及 main 目錄下面的py文件
  3. 接着 __init__ 或者 app 創建Flask對象
  4. 將 main 目錄下面的模塊文件註冊到藍圖對象中
  5. app.py 最終運行的就是 __init__.py 和 app.py 中的代碼 app 對象
Reference
  1. Flask-藍圖(blueprint)
  2. Python Flask 藍圖Blueprint
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章