Flask(9)- 藍圖的基本使用

小菠蘿測試筆記發表於2021-07-13

前言

  • 在前面的例子中,所有的頁面處理邏輯都是放在同一個檔案中,隨著業務程式碼的增加,將所有程式碼都放在單個程式檔案中是非常不合適的
  • 不僅會讓閱讀程式碼變得困難,而且會給後期維護帶來麻煩
  • Flask 中使用藍圖,提供了模組化管理程式路由的功能,使程式結構更加清晰

 

藍圖簡介

  • 隨著 Flask 程式越來越複雜,需要對程式進行模組化的處理
  • 藍圖 (Blueprint) 是 Flask 程式的模組化處理機制
  • 它是一個儲存檢視方法的集合
  • Flask 程式通過 Blueprint 來組織 URL 以及處理請求

 

Blueprint 具有以下屬性

  • 一個專案可以具有多個 Blueprint
  • Blueprint 可以單獨擁有自己的模板、靜態檔案的目錄
  • 在應用初始化時,註冊需要使用的 Blueprint

 

基本用法

功能概述

假設網站包含有如下 4 個頁面:

頁面功能處理函式
/news/society/ 社會新聞版塊 society_news
/news/tech/ IT 新聞版塊 tech_news
/products/car/ 汽車產品版塊 car_products
/products/baby/ 嬰幼兒產品版塊 baby_products
  • 前兩個都是 /news 字首,可以組成一個藍圖 news
  • 後兩個是 /products 字首,可以組成一個藍圖 products
  • 相當於四個檢視函式,兩個藍圖

 

程式中包含 4 個檢視函式,根據頁面路徑,Flask 將請求轉發給對應的檢視函式,從瀏覽器傳送過來的請求的處理過程如下圖所示

 

使用藍圖後,路由匹配流程

  1. 瀏覽器訪問路徑 /products/car
  2. Flask 框架在藍圖 news 和藍圖 products 中查詢匹配該頁面路徑的路由
  3. 發現在藍圖 products 中,存在和路徑 /products/car 匹配的檢視函式 car_products
  4. 最後將請求轉發給函式 car_products 處理

 

實戰小栗子

目錄結構

例子程式包括 2 個藍圖,由 3 個檔案構成:

  • app.py,程式的主檔案;
  • news.py,實現藍圖 news;
  • products.py,實現藍圖 products。

 

app.py 程式碼

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠蘿測試筆記
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/7/12 8:36 下午
# file: app.py
"""

# 匯入 Flask 和 藍圖 Blueprint
from flask import Flask, Blueprint

# 匯入藍圖類
from s7_blueprints import news
from s7_blueprints import products

app = Flask(__name__)

# 註冊藍圖
app.register_blueprint(news.blueprint)
app.register_blueprint(products.blueprint)

if __name__ == '__main__':
    app.run(debug=True)

 

news.py 程式碼

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠蘿測試筆記
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/7/12 8:36 下午
# file: news.py
"""

# 匯入藍圖
from flask import Blueprint

"""
例項化藍圖物件
第一個引數:藍圖名稱
第二個引數:匯入藍圖的名稱
第三個引數:藍圖字首,該藍圖下的路由規則字首都需要加上這個
"""
blueprint = Blueprint('news', __name__, url_prefix="/news")


# 用藍圖註冊路由
@blueprint.route("/society/")
def society_news():
    return "社會新聞板塊"


@blueprint.route("/tech/")
def tech_news():
    return "新聞板塊"

注意:頁面的絕對路徑是 /news/society/ 和 /news/tech/,因為藍圖的 url_prefix 設定為 news,在藍圖內部,頁面的相對路徑是 /society/ 和 /tech/

 

products.py 程式碼

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠蘿測試筆記
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/7/12 8:36 下午
# file: products.py
"""

from flask import Blueprint

blueprint = Blueprint("products", __name__, url_prefix="/product")


@blueprint.route("/car")
def car_products():
    return "汽車產品版塊"


@blueprint.route("/baby")
def baby_products():
    return "嬰兒產品版塊"

注意:頁面的絕對路徑是 /products/car/ 和 /product/baby/,因為藍圖的 url_prefix 等於 products,在藍圖內部,頁面的相對路徑是 /car/ 和 /baby/

 

postman 發起請求的結果

 

更具擴充套件性的架構

概述

隨著業務程式碼的增加,需要為 Flask 程式提供一個具備擴充套件性的架構,根據 Flask 程式的擴充套件性分為如下三種型別:

 

1、所有的頁面邏輯放在同一個檔案中

在這種架構中,程式完全不具備擴充套件性

在初學 Flask 時,使用的栗子都是這種型別

 

2、使用一個獨立的 Python 檔案實現藍圖

在這種架構中,程式具備一定的擴充套件性:

  • 程式由主程式和多個藍圖構成
  • 每個藍圖對應一個 Python 檔案
  • 所有的藍圖共享相同的模板檔案目錄
  • 所有的藍圖共享相同的靜態檔案目錄

上面的栗子就是採用這種架構

程式包含 2 個藍圖: news 和 products,由 3 個檔案構成:app.pynews.pyproducts.py,其中 news.py 實現新聞版塊,products.py 實現產品版塊

 

3、使用一個獨立的目錄實現藍圖

在這種架構中,程式的擴充套件性最好:

  • 程式由主程式和多個藍圖構成
  • 每個藍圖對應一個獨立的目錄,儲存與這個藍圖相關的檔案
  • 每個藍圖有一個獨立的模板檔案目錄
  • 每個藍圖有一個獨立的靜態檔案目錄

 

模板檔案尋找規則

每個藍圖可以擁有獨立的模板檔案目錄,模板檔案尋找規則如下:

  • 如果專案中的 templates 資料夾中存在相應的模板檔案,則使用 templates 資料夾下的模板檔案;
  • 如果專案中的 templates 資料夾中沒有相應的模板檔案,則使用定義藍圖的時候指定的 templates 資料夾下的模板檔案
  • 專案中的 templates 資料夾優先順序大於指定的 templates 資料夾

靜態檔案尋找規則

每個藍圖可以獨立的靜態檔案目錄,靜態檔案尋找規則如下:

  • 如果專案中的 static 資料夾中存在相應的靜態檔案,則使用 static 資料夾下的靜態檔案
  • 如果專案中的 static 資料夾中沒有相應的靜態檔案,則使用定義藍圖的時候指定的 static 資料夾下的靜態檔案
  • 專案中的 templates 資料夾優先順序大於指定的 templates 資料夾

 

究極擴充套件性的栗子

目錄結構

 

目錄功能描述

路徑功能描述
templates 專案預設的模板資料夾
static 專案預設的靜態資料夾
news 藍圖 news 的相關檔案
news/templates 藍圖 news 的私有模板資料夾
news/static 藍圖 news 的私有靜態資料夾
products 藍圖 products 的相關檔案
products/templates 藍圖 products 的私有模板資料夾
products/static 藍圖 products 的私有靜態資料夾
 

檔案功能描述

路徑功能描述
app.py 主程式
news/__init.py__ 藍圖 news 的實現
news/templates/society.html 屬於藍圖 news 的一個模板檔案
news/static/news.css 屬於藍圖 news 的一個靜態檔案
products/__init.py__ 藍圖 products 的實現

 

app.py 的程式碼

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠蘿測試筆記
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/7/12 10:39 下午
# file: 7_blueprint_app.py
"""

from flask import Flask

from s7_news import news
from s7_product import products

app = Flask(__name__)

app.register_blueprint(news.blueprint)
app.register_blueprint(products.blueprint)

app.run(debug=True)

 

news/__init.py__ 的程式碼

#!usr/bin/env python
# -*- coding:utf-8 _*-
"""
# author: 小菠蘿測試筆記
# blog:  https://www.cnblogs.com/poloyy/
# time: 2021/7/12 8:36 下午
"""

# 匯入藍圖
from flask import Blueprint, render_template

"""
例項化藍圖物件
第一個引數:藍圖名稱
第二個引數:匯入藍圖的名稱
第三個引數:藍圖字首,該藍圖下的路由規則字首都需要加上這個
"""
blueprint = Blueprint('news', __name__, url_prefix="/news", template_folder="templates", static_folder="static")


# 用藍圖註冊路由
@blueprint.route("/society/")
def society_news():
    return render_template('society.html')


@blueprint.route("/tech/")
def tech_news():
    return "IT 新聞板塊"
  • 藍圖中頁面的 URL 字首為 /news;
  • 藍圖的模板目錄為 templates,絕對路徑為 ‘專案目錄 /news/templates’;
  • 藍圖的靜態檔案目錄為 static,絕對路徑為 ‘專案目錄 /news/static’
  • 呼叫 render_template (‘society.html’) 渲染模板檔案 society.html,根據模板檔案的查詢規則,最終在 ‘專案目錄 /news/templates’ 目錄下找到模板檔案

 

news/templates/society.html 的程式碼

<link rel="stylesheet" href="{{ url_for('news.static',filename='news.css')}}">
<h1>社會新聞</h1>

 在模板檔案中引用了靜態檔案 news.css。{{url_for (‘news.static’,filename=‘news.css’) }} 的輸出為 news/static/news.css,其中 news.static 表示藍圖 news 的 static 目錄

 

news/static/news.css 的程式碼

h1 {
    color: red;
}

 

product.py/__init.py__ 的程式碼

from flask import Blueprint

blueprint = Blueprint('products', __name__, url_prefix='/products')

@blueprint.route("/car")
def car_products():
    return "汽車產品版塊"

@blueprint.route("/baby")
def baby_products():
    return "嬰兒產品版塊" 

 

瀏覽器訪問效果

訪問 http://localhost:5000/news/society/

 

驗證目錄優先順序

在根目錄下的 templates 目錄下也新增一個 society.html 檔案,在根目錄下的 static 目錄下新增一個 project.css

 

html 程式碼

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<link rel="stylesheet" href="{{ url_for('static',filename='project.css') }}">
<h1>社會新聞啊啊啊</h1>
</body>
</html>

 

css 程式碼

h1 {
    color: blue;
}

  

預期結果

  • 根據 templates、static 的查詢規則,會優先查詢專案根目錄的 templates、static 目錄下是否有對應的模板檔案、靜態檔案
  • 這裡 society.html 同時出現在根目錄的 templates 和藍圖目錄的 templates,應該優先返回根目錄的 templates 下的 society.html

 

瀏覽器訪問效果

符合預期結果

 

Blueprint 原始碼解析

類初始化 __init__ 方法引數列表

  • name:藍圖名稱,將會被新增到每個 endpoint 
  • import_name:藍圖包的名稱,通常是 __name__,有助於找到 root_path 藍圖
  • static_folder:包含靜態檔案的資料夾,由藍圖的靜態路由提供服務,路徑以藍圖檔案為根路徑開始找
  • static_url_path:提供靜態檔案的 url,預設就是 static_folder,如果藍圖沒有 url_prefix,應用程式的靜態路由將優先,並且藍圖的靜態檔案將無法訪問
  • template_folder:包含模板檔案的資料夾,路徑以藍圖檔案為根路徑開始找
  • url_prefix:會作為藍圖所有路由的字首路徑
  • subdomain:藍圖路由將匹配的子域
  • url_defaults:藍圖路由的預設值字典
  • root_path:預設情況下,藍圖會自動設定這基於“import_name”

 

相關文章