Flask 蓝图(Blueprint)是 Flask 中用于组织大型应用的强大工具。
下面我将从基础概念开始,逐步深入讲解蓝图的用法。
一、为什么需要蓝图?
1.1 小型应用的问题
在小型 Flask 应用中,我们通常把所有路由写在单个文件中:
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return "首页"
@app.route('/about')
def about():
return "关于我们"
@app.route('/contact')
def contact():
return "联系我们"
@app.route('/admin/dashboard')
def admin_dashboard():
return "管理员面板"
@app.route('/admin/users')
def admin_users():
return "用户管理"
问题:
- 所有路由混在一起,难以维护
- 功能模块没有分离
- 多人协作困难
- 代码复用性差
1.2 蓝图的解决方案
蓝图允许我们将应用划分为多个模块,每个模块可以:
- 有自己的路由
- 有自己的模板和静态文件
- 独立开发和测试
- 方便复用
二、蓝图基础
2.1 创建第一个蓝图
基本结构:
project/
├── app.py # 主应用
└── auth/ # 认证模块
├── __init__.py
└── routes.py
auth/init.py:
from flask import Blueprint
bp = Blueprint('auth', __name__)
from . import routes
auth/routes.py:
from . import bp
@bp.route('/login')
def login():
return "登录页面"
@bp.route('/logout')
def logout():
return "登出页面"
app.py:
from flask import Flask
from auth import bp as auth_bp
app = Flask(__name__)
app.register_blueprint(auth_bp, url_prefix='/auth')
@app.route('/')
def home():
return "首页"
2.2 蓝图参数详解
创建蓝图时的常用参数:
bp = Blueprint(
'auth', # 蓝图名称(必须唯一)
__name__, # 蓝图所在模块
url_prefix='/auth', # URL前缀(可选)
template_folder='templates', # 模板目录(可选)
static_folder='static' # 静态文件目录(可选)
)
三、蓝图进阶用法
3.1 蓝图资源组织
项目结构:
project/
├── app.py
├── auth/
│ ├── __init__.py
│ ├── routes.py
│ ├── templates/
│ │ └── auth/
│ │ └── login.html
│ └── static/
│ └── auth/
│ └── style.css
└── blog/
├── __init__.py
├── routes.py
└── templates/
└── blog/
└── post.html
模板命名空间:
为了避免模板冲突,建议在蓝图模板目录下创建子目录:
# auth/routes.py
@bp.route('/login')
def login():
return render_template('auth/login.html') # 使用 auth/login.html
3.2 蓝图静态文件
访问蓝图静态文件:
<!-- auth/templates/auth/login.html -->
<link href="{{ url_for('auth.static', filename='auth/style.css') }}" rel="stylesheet">
3.3 蓝图错误处理
每个蓝图可以有自己的错误处理器:
@bp.app_errorhandler(404)
def page_not_found(error):
return render_template('auth/404.html'), 404
四、蓝图高级特性
4.1 蓝图请求钩子
蓝图可以有自己的请求前/后钩子:
@bp.before_request
def before_request():
if not current_user.is_authenticated and request.endpoint != 'auth.login':
return redirect(url_for('auth.login'))
4.2 蓝图上下文处理器
使变量在所有蓝图的模板中可用:
@bp.context_processor
def inject_user():
return dict(current_user=current_user)
4.3 蓝图URL生成
在模板或视图函数中生成蓝图URL:
url_for('auth.login') # 生成 /auth/login
五、大型项目结构示例
项目结构:
flask_app/
├── config.py # 配置文件
├── app/ # 应用包
│ ├── __init__.py # 应用工厂
│ ├── auth/ # 认证蓝图
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ ├── forms.py
│ │ └── models.py
│ ├── blog/ # 博客蓝图
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── models.py
│ ├── static/ # 全局静态文件
│ ├── templates/ # 全局模板
│ └── extensions.py # 扩展初始化
├── migrations/ # 数据库迁移
└── tests/ # 测试
应用工厂模式:
# app/__init__.py
from flask import Flask
from .extensions import db, login_manager
def create_app(config_class='config'):
app = Flask(__name__)
app.config.from_object(config_class)
# 初始化扩展
db.init_app(app)
login_manager.init_app(app)
# 注册蓝图
from .auth import bp as auth_bp
from .blog import bp as blog_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
app.register_blueprint(blog_bp, url_prefix='/blog')
return app
六、最佳实践
-
命名规范:
- 蓝图名称使用单数形式(如
auth
而非auths
) - 模板子目录与蓝图名称一致
- 蓝图名称使用单数形式(如
-
模块划分原则:
- 按功能划分(如用户认证、博客、API)
- 每个蓝图保持独立性和完整性
- 避免蓝图间循环引用
-
性能考虑:
- 频繁使用的蓝图可以延迟注册
- 大型蓝图可以拆分为子蓝图
-
测试策略:
- 每个蓝图应有独立的测试文件
- 使用应用工厂便于测试
七、常见问题解答
Q1: 蓝图和 Flask 应用有什么区别?
A: 应用是 Flask 实例,蓝图是应用的组成部分。一个应用可以注册多个蓝图。
Q2: 什么时候应该使用蓝图?
A: 当项目有多个功能模块或需要代码复用时就应该使用蓝图。
Q3: 蓝图之间如何共享数据?
A: 可以通过应用上下文、数据库或共享模块来交换数据。
Q4: 蓝图能嵌套吗?
A: Flask 本身不支持蓝图嵌套,但可以通过组织代码实现类似效果。