Flask的藍圖和紅圖
1、藍圖
對於簡單的專案來說,比如專案就只有一個user模組,我們可以都將檢視函式定義在一個檔案裡面,不需要用到藍圖。
但是如果我們的專案有多個模組,如下有v1模組,v2模組.....等,那麼如果我們將這麼多的模組的檢視檔案都雜在一個檔案中去寫的話,就會導致管理非常不便:
如多人開發不同模組,會導致業務程式碼經常出現衝突,或者我們要棄用某個功能模組的話,需要去檔案中找到所有的相關功能程式碼並一一刪除......
這樣子做雖然沒錯,但是非常不符合pythonic的優雅,簡潔的特性。
根據pythonic的特性,我們肯定希望儘可能的將程式碼模組化,使我們的程式碼看起來更加的整潔和優雅,這時候flask的Blueprint就派上用場了。
如下,我們的package api下面有兩個模組,v1和v2,我們可以分別在v1和v2的__init__.py中,定義兩個藍圖v1和v2,然後在v1和v2下面的檔案中分別使用自定義的v1 v2兩個藍圖去實現相關路由
即藍圖就是一個儲存操作路由對映方法的容器,主要用來實現客戶端請求和url相互關聯的功能。
藍圖的實現方式如下:
from flask import Blueprint
def create_blueprint():
v1 = Blueprint("v1", __name__) # v1是自定義的藍圖的名稱, __name__表示當前模組名稱,此處也可以指明每個模組下面的靜態檔案和模板路徑template_folder="", static_folder=""
return v1
建立完成v1藍圖後,我們需要在例項化flask核心物件app時,將其註冊到flask核心物件app上
def register_blueprint(app):
from app.api.v1 import create_blueprint
bp_v1 = create_blueprint()
app.register_blueprint(bp_v1, url_prefix="/v1") # url_prefix是給註冊的藍圖新增路由字首。
def instance_app():
app = Flask(__name__)
register_blueprint(app)
return app
然後我們就可以在v1下面的book和user中使用我們的blueprint了。
2、紅圖
藍圖主要是用於模組級別的區分,並不適用於函式級別的區分的,如下圖,對於每個模組下面都有不同的檢視函式,為了區分這些不同的視同函式,我們需要自定義一個和藍圖有著相同功能的模組。這裡為了體現它和藍圖的異曲同工之妙,我們稱之為紅圖(redprint)
紅圖(redprint)的實現:
既然紅圖的功能和藍圖一樣,那麼紅圖的實現,我們自然可以參考藍圖的實現方式:
class Redprint():
def __init__(self, name):
self.name=name
self.mond = [] # 定義mond的作用在於,儲存每個繫結到紅圖上的function,url,options等
def route(self, url, **options): # 參考藍圖的使用,@bp_v1.route(url, method=["GET", "POST"])
def decorate(f): # 裝飾器的本質,就是對閉包的呼叫
self.mond.append((f, url, options))
return f
return decorate
def register(self, bp, url_prefix=None)
if url_prefix is None:
url_prefix = "/"+self.name
for f, url, options in self.mond:
endpoint = options.pop("endpoint", f.__name__) # 從options關鍵字引數中,取出endpoint,如果沒有傳遞endpoint引數,則使用被裝飾的方法名稱作為endpoint
bp.add_url_rule(url_prefix+url, endpoint, f, **options)
紅圖的使用:
在定義了紅圖實現類後,還是是上面的專案結構,在v1和v2包下的book和user檢視函式中分別使用紅圖(以book為例)
api = Redpint("book")
@api.route("get")
def get_book():
return "get book"
最後,需要將紅圖註冊到藍圖上:
在上面的建立藍圖的函式中,註冊紅圖:
from app.api.v1 import book, user
def create_blueprint():
bp_v1 = Blueprint("v1", __name__)
book.api.register(bp_v1)
user.api.register(bp_v1)
這樣,要在瀏覽器中輸入ip:post/v1/book/get 即可訪問v1下面的book中的get_book檢視函數了