藍(lán)圖 Blueprint
模塊化
隨著flask程序越來(lái)越復(fù)雜,我們需要對(duì)程序進(jìn)行模塊化的處理,之前學(xué)習(xí)過(guò)python的模塊化管理,于是針對(duì)一個(gè)簡(jiǎn)單的flask程序進(jìn)行模塊化處理
簡(jiǎn)單來(lái)說(shuō),Blueprint 是一個(gè)存儲(chǔ)視圖方法的容器,這些操作在這個(gè)Blueprint 被注冊(cè)到一個(gè)應(yīng)用之后就可以被調(diào)用,F(xiàn)lask 可以通過(guò)Blueprint來(lái)組織URL以及處理請(qǐng)求。
Flask使用Blueprint讓?xiě)?yīng)用實(shí)現(xiàn)模塊化,在Flask中,Blueprint具有如下屬性:
- 一個(gè)項(xiàng)目可以具有多個(gè)Blueprint
- 可以將一個(gè)Blueprint注冊(cè)到任何一個(gè)未使用的URL下比如 “/”、“/sample”或者子域名
- 在一個(gè)應(yīng)用中,一個(gè)模塊可以注冊(cè)多次
- Blueprint可以單獨(dú)具有自己的模板、靜態(tài)文件或者其它的通用操作方法,它并不是必須要實(shí)現(xiàn)應(yīng)用的視圖和函數(shù)的
- 在一個(gè)應(yīng)用初始化時(shí),就應(yīng)該要注冊(cè)需要使用的Blueprint
但是一個(gè)Blueprint并不是一個(gè)完整的應(yīng)用,它不能獨(dú)立于應(yīng)用運(yùn)行,而必須要注冊(cè)到某一個(gè)應(yīng)用中。
Blueprint對(duì)象用起來(lái)和一個(gè)應(yīng)用/Flask對(duì)象差不多,最大的區(qū)別在于一個(gè) 藍(lán)圖對(duì)象沒(méi)有辦法獨(dú)立運(yùn)行,必須將它注冊(cè)到一個(gè)應(yīng)用對(duì)象上才能生效
使用藍(lán)圖可以分為四個(gè)步驟
- 創(chuàng)建一個(gè)藍(lán)圖的包,例如users,并在
__init__.py文件中創(chuàng)建藍(lán)圖對(duì)象
users=Blueprint('users',__name__)
- 在這個(gè)藍(lán)圖目錄下, 創(chuàng)建views.py文件,保存當(dāng)前藍(lán)圖使用的視圖函數(shù)
@admin.route('/')
def home():
return 'user.home'
- 在users/init.py中引入views.py中所有的視圖函數(shù)
from flask import Blueprint
# 等同于原來(lái)在 manage.py里面的 app = Flask()
users=Blueprint('users',__name__)
from .views import *
- 在主應(yīng)用main.py文件中的app對(duì)象上注冊(cè)這個(gè)users藍(lán)圖對(duì)象
from users import users
app.register_blueprint(users,url_prefix='/users')
當(dāng)這個(gè)應(yīng)用啟動(dòng)后,通過(guò)/users/可以訪問(wèn)到藍(lán)圖中定義的視圖函數(shù)
運(yùn)行機(jī)制
- 藍(lán)圖是保存了一組將來(lái)可以在應(yīng)用對(duì)象上執(zhí)行的操作,注冊(cè)路由就是一種操作
- 當(dāng)在app對(duì)象上調(diào)用 route 裝飾器注冊(cè)路由時(shí),這個(gè)操作將修改對(duì)象的url_map路由表
- 然而,藍(lán)圖對(duì)象根本沒(méi)有路由表,當(dāng)我們?cè)谒{(lán)圖對(duì)象上調(diào)用route裝飾器注冊(cè)路由時(shí),它只是在內(nèi)部的一個(gè)延遲操作記錄列表defered_functions中添加了一個(gè)項(xiàng)
- 當(dāng)執(zhí)行app對(duì)象的 register_blueprint() 方法時(shí),應(yīng)用對(duì)象將從藍(lán)圖對(duì)象的 defered_functions 列表中取出每一項(xiàng),并以自身作為參數(shù)執(zhí)行該匿名函數(shù),即調(diào)用應(yīng)用對(duì)象的 add_url_rule() 方法,這將真正的修改應(yīng)用對(duì)象的usr_map路由表
藍(lán)圖的url前綴
- 當(dāng)我們?cè)趹?yīng)用對(duì)象上注冊(cè)一個(gè)藍(lán)圖時(shí),可以指定一個(gè)url_prefix關(guān)鍵字參數(shù)(這個(gè)參數(shù)默認(rèn)是/)

- 在應(yīng)用最終的路由表 url_map中,在藍(lán)圖上注冊(cè)的路由URL自動(dòng)被加上了這個(gè)前綴,這個(gè)可以保證在多個(gè)藍(lán)圖中使用相同的URL規(guī)則而不會(huì)最終引起沖突,只要在注冊(cè)藍(lán)圖時(shí)將不同的藍(lán)圖掛接到不同的自路徑即可
- url_for在使用時(shí),如果要生成一個(gè)藍(lán)圖里面的視圖對(duì)應(yīng)的路由地址,則需要聲明當(dāng)前藍(lán)圖名稱+視圖名稱
url_for('users.home') # /users/home
注冊(cè)藍(lán)圖中的靜態(tài)文件的相關(guān)路由
和應(yīng)用對(duì)象不同,藍(lán)圖對(duì)象創(chuàng)建時(shí)不會(huì)默認(rèn)注冊(cè)靜態(tài)目錄的路由。需要我們?cè)?創(chuàng)建時(shí)指定 static_folder 參數(shù)。
下面的示例將藍(lán)圖所在目錄下的static_users目錄設(shè)置為靜態(tài)目錄
# users/__init__.py,代碼:
user_blu = Blueprint("users",__name__,static_folder='static_users')
# 啟動(dòng)文件 main.py,代碼:
from users import user_blu
app.register_blueprint(user_blu,url_prefix='/users')
現(xiàn)在就可以使用/admin/static_admin/ 訪問(wèn)static_admin目錄下的靜態(tài)文件了 定制靜態(tài)目錄URL規(guī)則 :可以在創(chuàng)建藍(lán)圖對(duì)象時(shí)使用 static_url_path 來(lái)改變靜態(tài)目錄的路由。

下面的示例將為 static_admin 文件夾的路由設(shè)置為 /lib
admin = Blueprint("admin",__name__,static_folder='static_admin',static_url_path='/lib')
app.register_blueprint(admin,url_prefix='/admin')
設(shè)置藍(lán)圖中模版的目錄
藍(lán)圖對(duì)象默認(rèn)的模板目錄為系統(tǒng)的模版目錄,可以在創(chuàng)建藍(lán)圖對(duì)象時(shí)使用 template_folder 關(guān)鍵字參數(shù)設(shè)置模板目錄
創(chuàng)建藍(lán)圖中的模板目錄template_users :

admin = Blueprint('admin',__name__,template_folder='templates_users')

注:如果在 templates 中存在和 templates_users 有同名模板文件時(shí), 則系統(tǒng)會(huì)優(yōu)先使用 templates 中的文件
調(diào)整session配置
分析SQLAlachemy的構(gòu)造方式可以發(fā)現(xiàn),初始化并非一定要傳遞app應(yīng)用對(duì)象到內(nèi)部,事實(shí)上它提供了init_app方法給我們后續(xù)調(diào)用。而 init_app 方法是flask框架要求任何的第三方組件都要實(shí)現(xiàn)這個(gè)方法。
init_app方法內(nèi)部就是要第三方組件開(kāi)發(fā)者編寫(xiě)一些使用當(dāng)前組建的默認(rèn)配置項(xiàng)以及把當(dāng)前組件設(shè)置成一個(gè)對(duì)象,加載到app對(duì)象內(nèi)部extensions字典才能讓開(kāi)發(fā)者在flask框架內(nèi)部配置和使用當(dāng)前組件。
我們可以利用這種組件開(kāi)發(fā)機(jī)制,那么把配置代碼抽離出去。
配置文件中:
import redis
from flask_sqlalchemy import SQLAlchemy
# 創(chuàng)建db對(duì)象
db = SQLAlchemy()
class Config(object):
DEBUG = True
SECRET_KEY = "*(%#4sxcz(^(#$#8423"
# 數(shù)據(jù)庫(kù)鏈接配置:
#數(shù)據(jù)類型://登錄賬號(hào):登錄密碼@數(shù)據(jù)庫(kù)主機(jī)IP:數(shù)據(jù)庫(kù)訪問(wèn)端口/數(shù)據(jù)庫(kù)名稱
SQLALCHEMY_DATABASE_URI = "mysql://root:123@127.0.0.1:3306/flask_students"
# 設(shè)置mysql的錯(cuò)誤跟蹤信息顯示
SQLALCHEMY_TRACK_MODIFICATIONS = True
# 打印每次模型操作對(duì)應(yīng)的SQL語(yǔ)句
SQLALCHEMY_ECHO = True
"""把session保存到redis中"""
# session存儲(chǔ)方式為redis
# SESSION_TYPE="redis"
# # 如果設(shè)置session的生命周期是否是會(huì)話期, 為True,則關(guān)閉瀏覽器session就失效
# SESSION_PERMANENT = False
# # 是否對(duì)發(fā)送到瀏覽器上session的cookie值進(jìn)行加密
# SESSION_USE_SIGNER = False
# # 保存到redis的session數(shù)的名稱前綴
# SESSION_KEY_PREFIX = "session:"
# # session保存數(shù)據(jù)到redis時(shí)啟用的鏈接對(duì)象
# SESSION_REDIS = redis.Redis(host='127.0.0.1', port='6379') # 用于連接redis的配置
SESSION_TYPE= 'sqlalchemy' # session的存儲(chǔ)方式為sqlalchemy
SESSION_SQLALCHEMY= db # SQLAlchemy對(duì)象
SESSION_SQLALCHEMY_TABLE= 'sessions' # session要保存的表名稱
SESSION_PERMANENT= True # 如果設(shè)置為True,則關(guān)閉瀏覽器session就失效。
SESSION_USE_SIGNER= False # 是否對(duì)發(fā)送到瀏覽器上session的cookie值進(jìn)行加密
SESSION_KEY_PREFIX= 'session:' # 保存到session中的值的前綴
啟動(dòng)文件main.py,代碼:
from flask import Flask
from config import Config,db
from flask_session import Session
from flask import session
app = Flask(__name__,template_folder='templates')
app.config.from_object(Config)
# 把a(bǔ)pp加載到db對(duì)象中
db.init_app(app)
Session(app)
@app.route("/")
def index():
return "ok"
@app.route("/set_session")
def set_session():
"""設(shè)置session"""
session["username"] = "小明"
return "ok"
if __name__ == '__main__':
# db.create_all()
print( app.url_map )
app.run()