Blueprints
Blueprints 是 Flask 中组织大型应用的模块化方式,类似于 Django 的 app。
为什么使用 Blueprints
- 模块化: 将应用拆分为逻辑组件
- 可重用: 蓝图可以在多个应用间复用
- 组织性: 更好的代码结构和维护性
- URL 前缀: 为路由组设置统一前缀
基本结构
myapp/
├── app/
│ ├── __init__.py
│ ├── extensions.py
│ ├── config.py
│ ├── models/
│ │ ├── __init__.py
│ │ └── user.py
│ ├── blueprints/
│ │ ├── __init__.py
│ │ ├── auth.py
│ │ ├── main.py
│ │ └── api.py
│ ├── templates/
│ └── static/
├── migrations/
├── tests/
├── requirements.txt
└── run.py
创建蓝图
主应用工厂
# app/__init__.py
from flask import Flask
from .extensions import db, login_manager, migrate
from .config import Config
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
# 初始化扩展
db.init_app(app)
login_manager.init_app(app)
migrate.init_app(app, db)
# 注册蓝图
from .blueprints.main import bp as main_bp
app.register_blueprint(main_bp)
from .blueprints.auth import bp as auth_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
from .blueprints.api import bp as api_bp
app.register_blueprint(api_bp, url_prefix='/api/v1')
return app
扩展配置
# app/extensions.py
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager
from flask_migrate import Migrate
db = SQLAlchemy()
login_manager = LoginManager()
migrate = Migrate()
主蓝图
# app/blueprints/main.py
from flask import Blueprint, render_template
from flask_login import login_required
bp = Blueprint('main', __name__)
@bp.route('/')
def index():
return render_template('main/index.html')
@bp.route('/about')
def about():
return render_template('main/about.html')
@bp.route('/dashboard')
@login_required
def dashboard():
return render_template('main/dashboard.html')
认证蓝图
# app/blueprints/auth.py
from flask import Blueprint, render_template, redirect, url_for, flash
from flask_login import login_user, logout_user, login_required
from app.extensions import db
from app.models.user import User
from app.forms.auth import LoginForm, RegistrationForm
bp = Blueprint('auth', __name__)
@bp.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('注册成功!', 'success')
return redirect(url_for('auth.login'))
return render_template('auth/register.html', form=form)
@bp.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and user.check_password(form.password.data):
login_user(user, remember=form.remember_me.data)
return redirect(url_for('main.index'))
flash('登录失败', 'danger')
return render_template('auth/login.html', form=form)
@bp.route('/logout')
@login_required
def logout():
logout_user()
flash('已退出登录', 'info')
return redirect(url_for('main.index'))
API 蓝图
# app/blueprints/api.py
from flask import Blueprint, jsonify, request
from app.models.user import User
from app.extensions import db
bp = Blueprint('api', __name__)
@bp.route('/users', methods=['GET'])
def get_users():
users = User.query.all()
return jsonify([user.to_dict() for user in users])
@bp.route('/users/<int:id>', methods=['GET'])
def get_user(id):
user = User.query.get_or_404(id)
return jsonify(user.to_dict())
@bp.route('/users', methods=['POST'])
def create_user():
data = request.get_json()
user = User(username=data['username'], email=data['email'])
user.set_password(data['password'])
db.session.add(user)
db.session.commit()
return jsonify(user.to_dict()), 201
@bp.route('/users/<int:id>', methods=['PUT'])
def update_user(id):
user = User.query.get_or_404(id)
data = request.get_json()
user.username = data.get('username', user.username)
user.email = data.get('email', user.email)
db.session.commit()
return jsonify(user.to_dict())
@bp.route('/users/<int:id>', methods=['DELETE'])
def delete_user(id):
user = User.query.get_or_404(id)
db.session.delete(user)
db.session.commit()
return '', 204
蓝图配置
URL 前缀
# 所有路由自动添加前缀
app.register_blueprint(auth_bp, url_prefix='/auth')
# 访问 /auth/login, /auth/register
app.register_blueprint(api_bp, url_prefix='/api/v1')
# 访问 /api/v1/users
子域名
app.register_blueprint(api_bp, subdomain='api')
# 访问 api.example.com/users
静态文件
bp = Blueprint('auth', __name__,
static_folder='static',
static_url_path='/auth/static'
)
模板文件夹
bp = Blueprint('auth', __name__,
template_folder='templates/auth'
)
URL 生成
# 在蓝图中生成 URL
url_for('main.index') # -> /
url_for('auth.login') # -> /auth/login
url_for('api.get_users') # -> /api/v1/users
# 跨蓝图跳转
return redirect(url_for('main.index'))
蓝图错误处理
@bp.errorhandler(404)
def not_found(error):
return render_template('errors/404.html'), 404
@bp.errorhandler(500)
def internal_error(error):
db.session.rollback()
return render_template('errors/500.html'), 500
蓝图请求钩子
@bp.before_request
def before_request():
# 只对当前蓝图的路由生效
pass
@bp.after_request
def after_request(response):
return response
应用入口
# run.py
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run(debug=True)
下一步
学习如何测试 Flask 应用。