Flask-Blueprint


Flask-Blueprint(蓝图)是 Flask 中用于模块化组织应用的核心机制。当应用规模扩大时,所有路由、视图函数、静态文件和模板若都放在一个文件中,会导致代码臃肿、难以维护。蓝图可以将应用拆分为多个功能模块(如用户模块、商品模块、订单模块),每个模块独立管理自己的路由、视图、模板和静态资源,最终通过“注册”整合到主应用中,实现代码的解耦和复用。

一、为什么需要蓝图?

  • 模块化开发:将不同功能(如用户管理、内容发布)拆分为独立模块,每个模块有自己的路由、视图和资源。
  • 代码复用:蓝图可以被多个应用共享(如多个项目共用一个“用户认证”模块)。
  • 灵活扩展:通过注册/取消注册蓝图,动态启用或禁用功能模块。

二、蓝图的基本使用流程

蓝图的使用分为三步:创建蓝图 → 在蓝图中定义路由/视图 → 在主应用中注册蓝图

1. 项目结构(模块化示例)

假设一个博客应用,分为“用户模块(user)”和“文章模块(post)”,结构如下:

myblog/
├── app.py               # 主应用入口
├── user/                # 用户模块(蓝图)
│   ├── __init__.py      # 创建用户蓝图
│   ├── views.py         # 用户相关路由/视图
│   ├── templates/       # 用户模块专属模板
│   │   └── login.html
│   └── static/          # 用户模块专属静态文件
│       └── style.css
└── post/                # 文章模块(蓝图)
    ├── __init__.py      # 创建文章蓝图
    ├── views.py         # 文章相关路由/视图
    └── templates/
        └── post_list.html

2. 创建蓝图(user/__init__.py

在模块目录下,通过 Blueprint 类创建蓝图实例,指定蓝图名称和模块路径。

# user/__init__.py
from flask import Blueprint

# 创建用户蓝图:参数1=蓝图名,参数2=模块路径(__name__ 表示当前模块)
user_bp = Blueprint('user', __name__, 
                    template_folder='templates',  # 指定该蓝图的模板目录(可选)
                    static_folder='static')       # 指定该蓝图的静态文件目录(可选)

# 导入视图(必须在蓝图创建后,避免循环导入)
from . import views

3. 在蓝图中定义路由和视图(user/views.py

通过蓝图的 route 装饰器定义路由,用法与主应用的 @app.route 一致,但路由归属该蓝图。

# user/views.py
from flask import render_template, redirect, url_for
from . import user_bp  # 导入当前模块的蓝图

# 蓝图路由:登录页面(URL 最终会受注册时的前缀影响)
@user_bp.route('/login')
def login():
    # 渲染蓝图专属模板(默认先找应用的 templates,再找蓝图的 templates)
    return render_template('login.html')

# 蓝图路由:注册页面
@user_bp.route('/register')
def register():
    return '用户注册页面'

# 蓝图路由:用户中心(需登录后访问)
@user_bp.route('/profile')
def profile():
    return '用户中心'

4. 同理创建文章模块蓝图(post/__init__.pypost/views.py

# post/__init__.py
from flask import Blueprint

post_bp = Blueprint('post', __name__, template_folder='templates')

from . import views
# post/views.py
from . import post_bp

# 文章列表页
@post_bp.route('/list')
def post_list():
    return render_template('post_list.html')

# 文章详情页
@post_bp.route('/<int:post_id>')
def post_detail(post_id):
    return f'文章 {post_id} 的详情'

5. 在主应用中注册蓝图(app.py

通过 app.register_blueprint() 方法将蓝图注册到主应用,可指定 URL 前缀(避免不同模块路由冲突)。

# app.py
from flask import Flask
from user import user_bp  # 导入用户蓝图
from post import post_bp  # 导入文章蓝图

app = Flask(__name__)

# 注册用户蓝图:指定 URL 前缀为 /user(所有用户路由会自动加上 /user)
app.register_blueprint(user_bp, url_prefix='/user')

# 注册文章蓝图:指定 URL 前缀为 /post(所有文章路由会自动加上 /post)
app.register_blueprint(post_bp, url_prefix='/post')

# 主应用自身的路由(非蓝图路由)
@app.route('/')
def index():
    return '博客首页'

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

6. 访问蓝图路由

注册后,蓝图中的路由会自动拼接 URL 前缀:
- 用户模块路由:
- /user/login → 对应 user_bp.route('/login')
- /user/register → 对应 user_bp.route('/register')
- 文章模块路由:
- /post/list → 对应 post_bp.route('/list')
- /post/123 → 对应 post_bp.route('/<int:post_id>')
- 主应用路由:
- / → 对应 @app.route('/')

三、蓝图的模板与静态文件

蓝图可以有自己的 templatesstatic 目录,用于存放模块专属的资源,加载规则如下:

1. 模板文件(templates

  • 当调用 render_template('login.html') 时,Flask 会先在主应用的 templates 目录中查找 login.html
  • 若未找到,再到当前蓝图的 templates 目录中查找(即 user/templates/login.html)。

优势:主应用可以覆盖蓝图的模板(如自定义全局风格),蓝图也可保留自身专属模板。

2. 静态文件(static

蓝图的静态文件需通过 url_for 引用,格式为 url_for('蓝图名.static', filename='文件路径')

例如,在 user/templates/login.html 中引用用户模块的 style.css

<!-- user/templates/login.html -->
<link rel="stylesheet" href="{{ url_for('user.static', filename='style.css') }}">

生成的 URL 为:/user/static/style.css(因用户蓝图前缀为 /user)。

四、蓝图的高级用法

1. 蓝图的错误处理

蓝图可以定义专属的错误处理函数(如 404、500 错误),仅对该蓝图的路由生效。

# user/views.py
from flask import render_template
from . import user_bp

# 蓝图专属 404 错误处理(仅当访问 /user/* 路由出错时触发)
@user_bp.errorhandler(404)
def user_404(error):
    return render_template('user_404.html'), 404

2. 蓝图的 URL 反向解析

在模板或视图中,通过 url_for 生成蓝图路由的 URL 时,需指定“蓝图名.视图函数名”。

# 在主应用视图中生成用户登录页的 URL
from flask import url_for

@app.route('/')
def index():
    # url_for('蓝图名.视图函数名')
    login_url = url_for('user.login')  # 生成 /user/login
    post_list_url = url_for('post.post_list')  # 生成 /post/list
    return f'登录页:<a href="{login_url}">登录</a><br>文章列表:<a href="{post_list_url}">文章</a>'

3. 蓝图的命令(结合 Click)

蓝图可以定义自定义命令(通过 Flask 的 Click 集成),注册后可通过 flask 命令行调用。

# user/views.py
import click
from . import user_bp

# 定义蓝图专属命令(需用 @user_bp.cli.command() 装饰)
@user_bp.cli.command('create-admin')  # 命令名为 flask user create-admin
@click.argument('username')
def create_admin(username):
    """创建管理员用户"""
    print(f"创建管理员:{username}")

注册蓝图后,在终端执行:

flask user create-admin admin  # 输出:创建管理员:admin

五、蓝图的优势总结

  1. 模块化组织:将大型应用拆分为独立模块,每个模块管理自己的路由、视图和资源,代码结构清晰。
  2. 低耦合高内聚:模块间通过接口通信,修改一个模块不影响其他模块。
  3. 可复用性:蓝图可被多个应用导入和注册(如将“用户认证”模块复用到多个项目)。
  4. 灵活扩展:通过条件注册蓝图(如 if enable_feature: app.register_blueprint(...)),动态启用功能。

总结

Flask-Blueprint 是 Flask 模块化开发的核心工具,通过“创建蓝图 → 定义路由 → 注册蓝图”的流程,实现应用的拆分与整合。它解决了大型应用的代码臃肿问题,提高了代码的可维护性和复用性。在实际开发中,建议按功能模块(如用户、商品、订单)划分蓝图,每个蓝图独立管理自身的路由、模板和静态资源,让应用结构更清晰。

Flask-Blueprint

demo01_blueprint.py

"""
蓝图的基本使用【掌握】

- 作用:为了进行模块化开发
- 特点:属于flask中自带的,不需要安装扩展就能使用
- 蓝图的使用流程:
    - 1. 创建蓝图对象
    - 2. 使用蓝图装饰视图函数
    - 3. 将蓝图注册到app中
"""
from flask import Blueprint, Flask
from demo02_product import bp
from dmeo03_user import user_bp

app = Flask(__name__)

# 将蓝图注册到app中
app.register_blueprint(bp)
app.register_blueprint(user_bp)

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

demo02_product.py

from flask import Blueprint

# 创建蓝图对象
bp = Blueprint("myBp", __name__)


# 使用蓝图装饰视图函数
# 首页
@bp.route("/")
def index():
    return "index"


# 列表页
@bp.route("/list")
def list():
    return "list"


# 详情页
@bp.route("/detail")
def detail():
    return "detail"

dmeo03_user.py

from flask import Blueprint

# 创建蓝图对象
user_bp = Blueprint("user", __name__)


# 使用蓝图装饰视图函数
@user_bp.route("/user_info")
def user_info():
    return "user_info"

dmeo04_user_blue.py

from flask import Blueprint

# 1. 创建蓝图对象
# 参数1:user_blue,表示蓝图的名字,用来表示蓝图装饰的视图函数所属的蓝图
# 参数2:__name__,固定写法,表示的是蓝图所在的包的名字
# 参数3:static_folder,资源文件夹名字,
# 参数4:user_prefix,访问路径的前缀,为了防止资源混乱
# 参数5:template_folder,表示蓝图的模板文件。
#   如果app中也设置了自己的模板,且文件名相同,则优先访问app的
user_blue = Blueprint(
    "user_blue",
    __name__,
    static_folder="static",
    url_prefix="/user",
    template_folder="templates",
)

# 导入 view.py
from user import views
# view.py
from user import user_blue
from flask import render_template


# 2. 装饰视图函数
@user_blue.route("/user_login")
def user_login():
    return "user_login"


@user_blue.route("/register")
def register():
    return render_template("A01_blueprint.html")

A01_blueprint.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>用户注册</title>
</head>

<body>
    <h1>用户注册</h1>
    <h2>1、用户注册</h2>
    <div>哈哈哈哈哈哈哈哈哈哈哈哈</div>
</body>

</html>