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__.py 和 post/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('/')
三、蓝图的模板与静态文件
蓝图可以有自己的 templates 和 static 目录,用于存放模块专属的资源,加载规则如下:
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
五、蓝图的优势总结
- 模块化组织:将大型应用拆分为独立模块,每个模块管理自己的路由、视图和资源,代码结构清晰。
- 低耦合高内聚:模块间通过接口通信,修改一个模块不影响其他模块。
- 可复用性:蓝图可被多个应用导入和注册(如将“用户认证”模块复用到多个项目)。
- 灵活扩展:通过条件注册蓝图(如
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>