Flask中提供了藍圖,專門用做Flask的模塊化。對於藍圖,能夠看官方介紹,這裏翻譯過來的:html
Flask使用藍圖的概念來製做應用程序組件和支持應用程序內部或跨應用程序的通用模式。藍圖能夠大大簡化大型應用程序的工做方式,併爲Flask擴展提供了在應用程序上註冊操做的中心手段。Blueprint對象的工做方式與Flask應用程序對象相似,但實際上它不是一個應用程序。相反,它是如何構造或擴展應用程序的藍圖。flask
總之,藍圖可使咱們的程序更加模塊化,不一樣功能的路由能夠放在不一樣的模塊下,最後集中到啓動類中cookie
藍圖,聽起來就是一個很宏偉的東西session
在Flask中的藍圖 blueprint 也是很是宏偉的app
它的做用就是將 功能 與 主服務 分開怎麼理解呢?ide
好比說,你有一個客戶管理系統,最開始的時候,只有一個查看客戶列表的功能,後來你又加入了一個添加客戶的功能(add_user)模塊, 而後又加入了一個刪除客戶的功能(del_user)模塊,而後又加入了一個修改客戶的功能(up_user)模塊,在這個系統中,就能夠將模塊化
查看客戶,修改客戶,添加客戶,刪除客戶的四個功能作成藍圖加入到客戶管理系統中,本篇最後會作一個這樣的例子,可是首先咱們要搞清楚什麼是藍圖 blueprint函數
咱們先構建一個項目的目錄結構如圖所示:url
account.py的代碼:spa
from flask import Blueprint # 導入 Flask 中的藍圖 Blueprint 模塊 ac = Blueprint('ac', __name__) # 實例化一個藍圖(Blueprint)對象 @ac.route('/login/') # 這裏添加路由和視圖函數的時候與在Flask對象中添加是同樣的 def login(): return 'Login'
manager.py的代碼爲:
from flask import Flask # 導入此前寫好的藍圖模塊 from student_flask.account import ac app = Flask(__name__) # type:Flask # 在Flask對象中註冊藍圖模塊中的藍圖對象 ac app.register_blueprint(ac) if __name__ == '__main__': app.run(debug=True) # 如今Flask對象中並無寫任何的路由和視圖函數
啓動服務後訪問 http://127.0.0.1:5000/login/
能夠看到頁面返回
Login
上面的示例,咱們能夠看出在flask中咱們並無添加路由,可是咱們註冊了有路由和視圖函數的ac藍圖對象
在實例化藍圖的時候咱們能夠傳遞的一些參數
目錄結構爲
上面我把藍圖放在一個目錄下面,這個能夠根據我的的喜愛本身劃分
user.py的代碼爲
from flask import Blueprint # 導入 Flask 中的藍圖 Blueprint 模塊 from flask import render_template us = Blueprint("us", __name__, # 這裏是相對路徑,要加../ template_folder="../us_templates", # 每一個藍圖均可覺得本身獨立出一套template模板文件夾 # 若是不寫則共享項目目錄中的templates,而且他會先找和manager.py同級目錄下,再找student_flask static_folder="../us_static" # 靜態文件目錄也是能夠獨立出來的 ) # 實例化一個藍圖(Blueprint)對象 @us.route("/index/") def index(): return render_template("index.html")
index.html的代碼爲
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>Hello ! I am peiqi</p> <img src="/us_static/xiaozhu.jpg"> </body> </html>
manager.py的代碼爲
from flask import Flask # 導入此前寫好的藍圖模塊 from student_flask.views.account import ac from student_flask.views.user import us app = Flask(__name__) # type:Flask # 在Flask對象中註冊藍圖模塊中的藍圖對象 ac app.register_blueprint(ac) app.register_blueprint(us) if __name__ == '__main__': app.run(debug=True) # 如今Flask對象中並無寫任何的路由和視圖函數
啓動項目訪問http://127.0.0.1:5000/index/獲得
這個是否是最新很流行哈哈
從這個例子中咱們總結出:
Blueprint 其實能夠理解爲一個了沒有run方法的 Flask 對象
只要Blueprint被 Flask 註冊了,就必定會生效
注意了注意了注意了重要的事情說三遍
藍圖內部的視圖函數及route不要出現重複,不然你就能夠嚐嚐本身造的孽。
下面有一個情景:咱們在有的網頁訪問的時候咱們須要作一個簡單的認證,只有登錄的用戶能夠訪問匿名用戶不可以訪問。
這裏咱們的第一個方法讀取cookies中的session中的信息看看該用戶是否登錄沒登陸咱們就給他跳到登陸頁面。代碼以下
from flask import Blueprint, session, redirect, url_for, render_template ac = Blueprint('ac', __name__) @ac.route('/index') def index(): if not session.get('user'): return redirect(url_for('login')) return render_template('index.html')
上面寫的只是藍圖的代碼,其餘的請參考前面的寫法。
咱們上面只有一個index頁面若是咱們有很是多的頁面要咱們驗證上面的方法是否是很是繁瑣,且代碼重複。
這裏咱們就想到了裝飾器,
from flask import Blueprint, session, redirect, url_for, render_template import functools ac = Blueprint('ac', __name__) def auth(func): @functools.wraps(func) def inner(*args, **kwargs): if not session.get('user'): return redirect(url_for('login')) ret = func(*args, **kwargs) return ret return inner @ac.route('/index') @auth def index(): return render_template('index.html')
上面就是咱們使用裝飾器達到的效果,在這裏咱們知道若是咱們有成千上萬個頁面須要驗證只有個別的不須要驗證那每次前面都要加@auth是否是有點麻煩,且有時候還有可能忘記加了。
因此在這裏咱們仍是感受有點麻煩。因此使用下面的方法三也就是befor_request
使用before_request。
from flask import Blueprint, session, redirect, url_for, render_template, request ac = Blueprint('ac', __name__) @ac.before_request # 這個就至關於Django中的中間件 def is_login(): # 判斷是否登錄的函數 if request.path == '/login/': # 設置的白名單 return None if session.get('user'): return None return redirect('/login') @ac.route('/login/') def login(): return 'Login'
注意:上面咱們的這個裝飾器是寫在一個藍圖裏面的因此這個裝飾器也就只對這個藍圖起做用屬於局部的,要想全局起做用就在註冊藍圖的地方寫這個特殊的裝飾器。
還有上面用到的是藍圖因此在使用session的時候咱們在上面沒有設置配置裏面的參數:SECRET_KEY = "qwerdf"。
完整目錄以下
全局的特殊裝飾器卸載__init__.py裏面。咱們對flask的配置通常都寫在settings裏面。
@app.before_request 也是一個裝飾器,他所裝飾的函數,都會在請求進入視圖函數以前執行
request.path 是來讀取當前的url地址若是是 /login 就容許直接經過 return None 你能夠理解成經過放行
校驗session中是否有user 若是沒有的話,證實沒有登陸,因此絕不留情的 redirect("/login") 跳轉登陸頁面
還有一個要提的 @app.before_first_request 它與 @app.before_request 極爲類似或者說是如出一轍,只不過它只會被執行一次
@app.before_request修飾器在開發中用處很是大,好比判斷某個ip是否有惡意訪問行爲,從而進行攔截等操做
after_request和before_request對應,它是在響應(response)以前作出響應
from flask import Flask app = Flask(__name__) @app.after_request def after1(response): print('after:1') return response @app.route('/index/') def index(): print('index') return "Index" if __name__ == '__main__': app.run()
上面代碼當咱們訪問http://127.0.0.1:5000/index/的時候咱們能夠在控制檯看到
index
after:1
從結果能夠看出咱們是在執行index函數後執行after_request這個特殊的裝飾器,也就是說當用戶的請求獲得響應的時候纔會執行after_request.
這裏注意了若是和上面同樣使用了藍圖來開發,那麼咱們after_request寫的位置決定了他是在全部的藍圖其效果仍是在單個藍圖裏面其效果。
以下示例:
from flask import Flask app = Flask(__name__) @app.before_request def before1(): print('before:1') @app.before_request def before2(): print('before:2') @app.after_request def after1(response): print('after:1') return response @app.after_request def after2(response): print('after:2') return response @app.route('/index/') def index(): print('index') return "Index" if __name__ == '__main__': app.run()
當咱們訪問http://127.0.0.1:5000/index/的時候在管理控制檯咱們能夠看到
before:1
before:2
index
after:2
after:1
從上面的結果咱們能夠看出before_request誰寫在前面,當咱們訪問某個視圖的時候就先執行誰,而after_request相反,寫在前面的後執行。
若是有一個before_request有返回值那麼這個請求會怎麼走?看一段代碼
from flask import Flask app = Flask(__name__) @app.before_request def before1(): print('before:1') return "before:1" @app.before_request def before2(): print('before:2') @app.after_request def after1(response): print("after:1") return response @app.after_request def after2(response): print("after:2") return response @app.route('/index/') def index(): print('index') return "Index" if __name__ == '__main__': app.run(debug=True)
運行上面的代碼,而後訪問http://127.0.0.1:5000/
咱們在控制檯能夠看到
before:1
127.0.0.1 - - [30/Jan/2019 14:53:48] "GET / HTTP/1.1" 200 -
after:2
after:1
當請求來的時候,在第一個before_request咱們有返回值的時候,程序就會直接跳過視圖函數,執行after_request,執行的順序仍是先執行靠近視圖函數的位置。
同時頁面會返回前面要返回的信息。
啓動flask的時候處理第第一個請求的時候會被執行,接下來的請求不會被執行, 而before_request則表示每個請求都會執行該特殊的裝飾器。
並且當第一個請求執行的時候會先執行before_first_request在執行before_request,代碼以下:
from flask import Flask app = Flask(__name__) @app.before_request def xx1(): print('before_request') @app.before_first_request def x1(): print('before_first_request') @app.route('/index/') def index(): print('index') return "Index" @app.route('/order/') def order(): print('order') return "order" if __name__ == '__main__': app.run(debug=True)
咱們先訪問:http://127.0.0.1:5000/index/,在訪問http://127.0.0.1:5000/order/
在管理控制檯咱們能夠看到:
before_first_request
127.0.0.1 - - [30/Jan/2019 17:30:30] "GET /index/ HTTP/1.1" 200 -
before_request
index
before_request
127.0.0.1 - - [30/Jan/2019 17:30:37] "GET /order/ HTTP/1.1" 200 -
order
從上面能夠看到當咱們訪問index的時候屬於程序的第一次訪問因此會執行before_first_request,當咱們在訪問order的時候,就沒有執行before_first_request。
注意:當咱們使用的訪問地址爲'/index/',當咱們訪問http://127.0.0.1:5000/index,在我這裏會自動重定向到http://127.0.0.1:5000/index/這個時候就至關於發送了2次請求。
不知道這個是否是我我的狀況。
這個能夠定義一些頁面顯示想要的畫面,好比訪問出現404的時候不想要他出現404而是出現本身想要頁面。
from flask import Flask app = Flask(__name__) @app.errorhandler(404) def not_found(arg): print(arg) return "沒找到" @app.route('/index/') def index(): print('index') return "Index" if __name__ == '__main__': app.run(debug=True)
訪問一個不存在的頁面會看到頁面
沒找到 這三個字