Flask 教程

Flask 蓝图 (Blueprints)

蓝图(Blueprints) 是 Flask 实现模块化开发的核心机制。

当一个 Flask 项目变得越来越大,把所有的路由、视图函数、模板都塞进一个 app.py 文件会导致代码难以维护。蓝图允许你将应用拆分成多个独立的组件(模块),最后再将这些组件“注册”到主应用中。

你可以把主应用(App)想象成一家总公司,而蓝图(Blueprint)就是旗下的分公司(如:人力资源部、财务部、技术部)。每个分公司有自己的职能和规则,但都归属于总公司管理。


🏗️ 1. 为什么需要蓝图?

  • 代码解耦:将不同功能的代码(如用户认证、博客文章、API 接口)分开存放。
  • 易于协作:不同的开发者可以负责不同的蓝图,减少代码冲突。
  • URL 前缀管理:可以轻松为整个模块添加 URL 前缀(例如所有 API 接口都以 /api/v1 开头)。
  • 独立资源:每个蓝图可以拥有自己独立的模板文件夹和静态文件文件夹。

🛠️ 2. 如何创建和使用蓝图?

假设我们要构建一个简单的博客系统,包含两个模块:

  1. main:主页、关于页面。
  2. auth:登录、注册。

第一步:目录结构

纯文本
plaintext
my_project/
├── app.py                # 主应用入口
├── main/                 # 主模块蓝图
│   ├── __init__.py       # 定义蓝图
│   └── routes.py         # 主模块路由
└── auth/                 # 认证模块蓝图
    ├── __init__.py       # 定义蓝图
    └── routes.py         # 认证模块路由

第二步:定义蓝图 (main/__init__.py)

纯文本
plaintext
from flask import Blueprint

# 创建蓝图实例
# 'main' 是蓝图名称
# __name__ 帮助 Flask 定位资源路径
main_bp = Blueprint('main', __name__)

# 注意:这里不要导入 routes,否则会造成循环引用
# 我们在下面单独导入
from . import routes 

第三步:编写路由 (main/routes.py)

纯文本
plaintext
from . import main_bp  # 从当前包导入蓝图

@main_bp.route('/')
def index():
    return '这是主页 (Main Blueprint)'

@main_bp.route('/about')
def about():
    return '关于我们 (Main Blueprint)'

第四步:定义另一个蓝图 (auth/__init__.py & routes.py)

auth/__init__.py:

纯文本
plaintext
from flask import Blueprint

auth_bp = Blueprint('auth', __name__, url_prefix='/auth') 
# url_prefix: 可选参数,给该蓝图下所有路由自动加上 /auth 前缀

from . import routes

auth/routes.py:

纯文本
plaintext
from . import auth_bp

@auth_bp.route('/login')
def login():
    return '登录页面 (Auth Blueprint) -> 实际访问路径: /auth/login'

@auth_bp.route('/register')
def register():
    return '注册页面 (Auth Blueprint) -> 实际访问路径: /auth/register'

第五步:在主应用中注册蓝图 (app.py)

纯文本
plaintext
from flask import Flask
from main import main_bp
from auth import auth_bp

app = Flask(__name__)

# 注册蓝图
app.register_blueprint(main_bp)      # 挂载到根路径
app.register_blueprint(auth_bp)      # 挂载到 /auth 路径 (因为蓝图定义时指定了 prefix)

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

🔍 3. 蓝图的关键特性

A. URL 前缀 (url_prefix)

在注册蓝图或创建蓝图时,可以指定前缀。

纯文本
plaintext
# 方式 1:创建时指定
api_bp = Blueprint('api', __name__, url_prefix='/api/v1')

# 方式 2:注册时指定
app.register_blueprint(api_bp, url_prefix='/api/v2')

如果蓝图中有一个路由 @api_bp.route('/users'),最终访问路径将是 /api/v1/users/api/v2/users

B. 独立的模板和静态文件

默认情况下,Flask 会在主应用的 templatesstatic 文件夹中查找资源。但蓝图可以拥有自己的资源文件夹。

纯文本
plaintext
# 在创建蓝图时指定
admin_bp = Blueprint(
    'admin', 
    __name__,
    template_folder='templates',  # 蓝图目录下的 templates 文件夹
    static_folder='static'        # 蓝图目录下的 static 文件夹
)

注意:在模板中引用静态文件时,端点名称会变成 蓝图名.static

纯文本
plaintext
<!-- 引用 admin 蓝图的静态文件 -->
<link rel="stylesheet" href="{{ url_for('admin.static', filename='style.css') }}">

C. 请求钩子 (Before/After Request)

蓝图也可以定义自己的 before_requestafter_request,但它们只对该蓝图内的路由生效

纯文本
plaintext
@admin_bp.before_request
def check_admin_permission():
    if not session.get('is_admin'):
        return redirect(url_for('auth.login'))

如果你希望某个钩子对全局生效,必须在主 app 上定义,而不是在蓝图上。


💡 4. 最佳实践:应用工厂 + 蓝图

在大型项目中,通常结合应用工厂模式使用蓝图。

app/__init__.py:

纯文本
plaintext
from flask import Flask
from config import Config

def create_app(config_class=Config):
    app = Flask(__name__)
    app.config.from_object(config_class)

    # 初始化扩展 (db, login_manager 等)
    from extensions import db, migrate
    db.init_app(app)
    migrate.init_app(app, db)

    # 注册蓝图
    from app.main.routes import main_bp
    from app.auth.routes import auth_bp

    app.register_blueprint(main_bp)
    app.register_blueprint(auth_bp, url_prefix='/auth')

    return app

⚠️ 常见陷阱

  1. 循环导入 (Circular Import)
    • 错误做法:在 blueprint/__init__.py 中直接 import routes,而 routes.pyimport blueprint
    • 正确做法:在 __init__.py 的最后导入 routes,或者确保 routes.py 只导入蓝图实例,不导入其他可能依赖 app 的对象。
  2. 端点名称冲突
    • 每个视图函数都有一个唯一的“端点名称”(默认是函数名)。如果两个蓝图有同名函数(如都有 index()),Flask 会自动处理为 blueprint_name.function_name
    • 在使用 url_for() 时,跨蓝图跳转必须指定蓝图名前缀:
      python # 在 main 蓝图中跳转到 auth 蓝图的 login url_for('auth.login')

📝 总结

特性说明
核心作用模块化组织代码,避免单文件过大
创建方法bp = Blueprint('name', __name__)
注册方法app.register_blueprint(bp)
URL 前缀可在创建或注册时通过 url_prefix 设置
资源隔离支持独立的 template_folderstatic_folder
适用场景任何超过 5-10 个路由的项目都应使用蓝图

掌握了蓝图,你的 Flask 项目就具备了支撑中大型应用的结构基础。接下来,你想学习如何连接数据库 (SQLAlchemy) 并在蓝图中操作数据,还是学习如何部署你的 Flask 应用?

发表回复

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