Flask 教程

Flask Blueprint 蓝图对象 API

蓝图(Blueprint) 是 Flask 中用于模块化组织代码的核心对象。它本质上是一个“未注册的应用”,包含了一组路由、错误处理器、模板和静态文件配置,但只有在被主应用(app)注册后才会生效。

理解 Blueprint 对象的 API,能帮你更好地实现代码解耦和复用。


🏗️ 1. 创建蓝图对象

蓝图的构造函数非常灵活,允许你定义其资源路径和前缀。

纯文本
plaintext
from flask import Blueprint

# 基本用法
my_bp = Blueprint('name', __name__)

# 高级用法:指定独立的模板和静态文件夹
admin_bp = Blueprint(
    'admin', 
    __name__,
    template_folder='templates',      # 默认为 'templates'
    static_folder='static',           # 默认为 'static'
    static_url_path='/admin_static',  # URL 访问前缀,默认为 /static
    url_prefix='/admin'               # 路由前缀,注册时可覆盖
)

参数详解:

  • name: 蓝图的唯一标识名,用于 url_for('name.endpoint')
  • import_name: 通常是 __name__,用于定位资源根目录。
  • template_folder: 相对于蓝图所在目录的模板文件夹路径。
  • static_folder: 相对于蓝图所在目录的静态文件夹路径。
  • static_url_path: 浏览器访问静态文件的 URL 路径。
  • url_prefix: 最常用。给该蓝图下所有路由自动加上前缀(如 /api/v1)。

🛠️ 2. 核心 API 方法

蓝图对象拥有与 Flask 应用对象几乎相同的装饰器和注册方法。

A. 路由注册

  • @bp.route(rule, **options): 注册视图函数。
  • bp.add_url_rule(rule, endpoint=None, view_func=None, **options): 底层注册方法。

B. 错误处理

  • @bp.errorhandler(code_or_exception): 注册仅对该蓝图生效的错误处理器。
    • 注意:如果蓝图中没有定义该错误的处理器,Flask 会 fallback 到主应用的处理器。

C. 生命周期钩子

  • @bp.before_request: 仅在该蓝图的路由被调用前执行。
  • @bp.after_request: 仅在该蓝图的路由执行后执行。
  • @bp.teardown_request: 请求结束时执行。
  • @bp.before_app_request: 全局钩子。即使定义在蓝图中,也会对整个应用的所有请求生效。
  • @bp.after_app_request: 全局钩子。对整个应用的所有响应生效。

D. 模板与上下文

  • @bp.context_processor: 注入模板变量,仅对该蓝图的模板生效。
  • @bp.app_context_processor: 注入模板变量,对整个应用的模板生效。
  • @bp.template_filter(name): 注册仅在该蓝图中可用的 Jinja2 过滤器。
  • @bp.template_global(): 注册全局可用的模板函数/变量。

E. 静态文件

  • 蓝图自动拥有一个名为 <blueprint_name>.static 的端点。
    • 用法:url_for('admin.static', filename='style.css')

🔌 3. 注册蓝图到应用

蓝图本身不能运行,必须通过 app.register_blueprint() 挂载到主应用上。

纯文本
plaintext
app.register_blueprint(
    my_bp, 
    url_prefix='/api',          # 可选:覆盖或补充蓝图定义的前缀
    subdomain='api',            # 可选:绑定特定子域名
    name_prefix='v1_'           # 可选:给所有端点名称加前缀 (Flask 2.0+)
)

💡 4. 关键概念:端点名称 (Endpoint Name)

这是新手最容易混淆的地方。每个视图函数都有一个唯一的“端点名”,默认等于函数名。

  • 主应用中的视图:端点名为 function_name
  • 蓝图中的视图:端点名为 blueprint_name.function_name

示例:

纯文本
plaintext
# main_bp.py
@main_bp.route('/')
def index():
    pass

# auth_bp.py
@auth_bp.route('/login')
def login():
    pass

在模板或代码中使用 url_for 时:

  • 跳转主页:url_for('main.index')
  • 跳转登录:url_for('auth.login')

技巧:如果你在蓝图内部想引用当前蓝图的其他路由,可以使用相对引用 .endpoint_name(例如 url_for('.login')),Flask 会自动补全蓝图名前缀。


⚠️ 5. 常见陷阱与最佳实践

A. 循环导入 (Circular Import)

问题app.py 导入 blueprint,而 blueprint 又导入 appmodels(依赖 app)。
解决

  1. 将蓝图实例 (bp = Blueprint(...)) 放在单独的 __init__.pyviews.py 顶部。
  2. __init__.py最后导入 routes 模块。
  3. 使用 current_app 代替直接导入 app

B. 静态文件路径冲突

如果多个蓝图都使用默认的 static_folder='static',它们的静态文件 URL 可能会冲突或被主应用的 /static 覆盖。
建议:为每个蓝图设置独特的 static_url_path,或者统一使用主应用的静态文件夹。

C. 模板查找顺序

当渲染模板时,Flask 的查找顺序是:

  1. 主应用的 templates/ 文件夹。
  2. 已注册蓝图的 templates/ 文件夹(按注册顺序)。
    建议:为了避免命名冲突,建议在蓝图模板文件夹内再建一层子目录,如 templates/admin/dashboard.html,并在渲染时使用完整路径 render_template('admin/dashboard.html')

📝 总结:Blueprint vs App API 对比

功能Flask App (app)Blueprint (bp)备注
路由@app.route@bp.route语法完全一致
错误处理@app.errorhandler@bp.errorhandler蓝图优先,找不到则找 App
前置钩子@app.before_request@bp.before_request蓝图钩子只影响蓝图路由
全局钩子N/A@bp.before_app_request蓝图也能定义影响全局的钩子
配置app.config无独立配置蓝图共享 current_app.config
运行app.run()❌ 不可运行蓝图只是组件

掌握了 Blueprint API,你就拥有了构建大型、可维护 Flask 项目的基石。接下来,你可以尝试将一个单体应用拆分为 auth, api, main 三个蓝图,体验模块化的魅力!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注