#项目架构重构(Blueprints):将代码模块化拆分
📂 所属阶段:第四阶段 — 实战演练(道满博客)
🔗 相关章节:路由(Routing)艺术 · Flask-Login 实战
#1. 为什么需要 Blueprints?
#1.1 无蓝图的问题
app.py(单文件,5000 行)😱
├── 首页路由
├── 登录路由
├── 注册路由
├── 文章列表路由
├── 文章详情路由
├── 文章发布路由
├── 评论路由
├── 搜索路由
├── 管理后台路由
├── API 路由
└── 错误处理#1.2 蓝图的优势
蓝图 = 模块化功能单元
每个蓝图管理自己的一组路由、模板和静态文件
蓝图拆分后:
├── app/
│ ├── __init__.py # 应用工厂
│ ├── extensions.py # 扩展
│ ├── main/ # 主蓝图
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates/
│ │ └── main/
│ ├── auth/ # 认证蓝图
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates/
│ │ └── auth/
│ ├── articles/ # 文章蓝图
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates/
│ │ └── articles/
│ ├── admin/ # 管理后台蓝图
│ │ ├── __init__.py
│ │ └── routes.py
│ └── api/ # API 蓝图
│ ├── __init__.py
│ └── routes.py
└── run.py#2. 创建蓝图
#2.1 主蓝图(首页、关于页)
# app/main/__init__.py
from flask import Blueprint
main_bp = Blueprint("main", __name__)
from . import routes# app/main/routes.py
from flask import render_template
from app.main import main_bp
@main_bp.route("/")
def index():
return render_template("main/index.html")
@main_bp.route("/about")
def about():
return render_template("main/about.html")#3. 认证蓝图
# app/auth/__init__.py
from flask import Blueprint
auth_bp = Blueprint("auth", __name__, url_prefix="/auth")
from . import routes# app/auth/routes.py
from flask import render_template, redirect, url_for, flash, request
from flask_login import login_user, logout_user, login_required, current_user
from werkzeug.security import generate_password_hash, check_password_hash
from app.auth import auth_bp
from app.extensions import db
from app.models import User
from app.forms import LoginForm, RegisterForm
@auth_bp.route("/login", methods=["GET", "POST"])
def login():
if current_user.is_authenticated:
return redirect(url_for("main.index"))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.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)
@auth_bp.route("/logout")
@login_required
def logout():
logout_user()
flash("已退出登录。", "info")
return redirect(url_for("auth.login"))#4. 文章蓝图
# app/articles/__init__.py
from flask import Blueprint
articles_bp = Blueprint("articles", __name__, url_prefix="/articles")
from . import routes# app/articles/routes.py
from flask import render_template, redirect, url_for, flash, abort, request
from flask_login import login_required, current_user
from app.articles import articles_bp
from app.extensions import db
from app.models import Post, Category
from app.forms import ArticleForm
@articles_bp.route("/")
def index():
page = request.args.get("page", 1, type=int)
pagination = Post.query.filter_by(is_published=True)\
.order_by(Post.created_at.desc())\
.paginate(page=page, per_page=10, error_out=False)
return render_template("articles/index.html", pagination=pagination)
@articles_bp.route("/<int:post_id>")
def detail(post_id):
post = Post.query.get_or_404(post_id)
post.views += 1
db.session.commit()
return render_template("articles/detail.html", post=post)
@articles_bp.route("/create", methods=["GET", "POST"])
@login_required
def create():
form = ArticleForm()
if form.validate_on_submit():
post = Post(
title=form.title.data,
content=form.content.data,
summary=form.summary.data,
author=current_user,
)
if form.is_published.data:
post.is_published = True
db.session.add(post)
db.session.commit()
flash("文章发布成功!", "success")
return redirect(url_for("articles.detail", post_id=post.id))
return render_template("articles/create.html", form=form)#5. 在应用工厂中注册蓝图
# app/__init__.py
from flask import Flask
from app.extensions import db, login_manager
def create_app():
app = Flask(__name__)
# 初始化扩展
db.init_app(app)
login_manager.init_app(app)
# 注册蓝图
from app.main import main_bp
from app.auth import auth_bp
from app.articles import articles_bp
app.register_blueprint(main_bp)
app.register_blueprint(auth_bp)
app.register_blueprint(articles_bp)
# 用户加载器
@login_manager.user_loader
def load_user(user_id):
return db.session.get(User, int(user_id))
return app#6. 小结
# 蓝图速查
# 创建蓝图
bp = Blueprint("name", __name__, url_prefix="/prefix")
# 注册路由
@bp.route("/path")
def handler(): ...
# 注册到应用
app.register_blueprint(bp)
# url_for 生成 URL
url_for("name.handler") # name = Blueprint 的第一个参数💡 最佳实践:每个蓝图对应一个功能模块,有自己的路由、模板和静态文件。蓝图之间通过
url_for("other_bp.handler")相互引用。
🔗 扩展阅读

