路由(Routing)艺术:变量规则、HTTP 方法与唯一 URL

📂 所属阶段:第一阶段 — 破冰启航(基础篇)
🔗 相关章节:初识 Flask · Jinja2 模板引擎


1. 路由基础

1.1 定义路由

from flask import Flask, jsonify

app = Flask(__name__)

@app.route("/")
def index():
    return "<h1>欢迎来到道满博客!</h1>"

@app.route("/about")
def about():
    return "<p>关于道满</p>"

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

1.2 路由装饰器原理

# 装饰器等价于:
def index():
    return "<h1>欢迎!</h1>"

index = app.route("/")(index)

2. 路径变量(动态路由)

2.1 基本用法

@app.route("/user/<username>")
def show_user(username):
    return f"<h1>用户:{username}</h1>"

@app.route("/post/<int:post_id>")
def show_post(post_id):
    return f"<h1>文章ID:{post_id}</h1>"

@app.route("/article/<path:subpath>")
def show_article(subpath):
    return f"文章路径:{subpath}"

2.2 变量类型

转换器说明示例
string默认,不含斜杠的字符串/user/john
int整数/post/42
float浮点数/rate/3.14
path含斜杠的路径/file/path/to/doc
uuidUUID 格式/item/550e8400-e29b-41d4-a716-446655440000
any指定多个值/item/<any(a,b):action>
@app.route("/item/<any(edit,delete,view):action>")
def item_action(action):
    return f"执行操作:{action}"

# 访问 /item/edit → action="edit"
# 访问 /item/delete → action="delete"

2.3 多个路径变量

@app.route("/blog/<int:year>/<int:month>/<slug>")
def blog_archive(year, month, slug):
    from datetime import datetime
    date = datetime(year, month, 1)
    return f"<h1>{date.strftime('%Y年%m月')}</h1><p>{slug}</p>"

# 访问 /blog/2026/3/getting-started
# → year=2026, month=3, slug="getting-started"

3. HTTP 方法

3.1 基础方法

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        # 处理登录逻辑
        return redirect(url_for("dashboard"))
    return render_template("login.html")

3.2 RESTful HTTP 方法

@app.route("/articles/<int:article_id>", methods=["GET"])
def get_article(article_id):
    """获取文章"""
    article = Article.query.get_or_404(article_id)
    return render_template("article.html", article=article)

@app.route("/articles", methods=["POST"])
def create_article():
    """创建文章"""
    # 从 request.form 获取数据
    title = request.form.get("title")
    content = request.form.get("content")
    new_article = Article(title=title, content=content)
    db.session.add(new_article)
    db.session.commit()
    return redirect(url_for("article", article_id=new_article.id))

@app.route("/articles/<int:article_id>/edit", methods=["GET", "POST"])
def edit_article(article_id):
    """编辑文章"""
    article = Article.query.get_or_404(article_id)
    if request.method == "POST":
        article.title = request.form.get("title")
        db.session.commit()
        flash("文章已更新!")
        return redirect(url_for("article", article_id=article.id))
    return render_template("edit_article.html", article=article)

@app.route("/articles/<int:article_id>/delete", methods=["POST"])
def delete_article(article_id):
    """删除文章(禁止 GET)"""
    article = Article.query.get_or_404(article_id)
    db.session.delete(article)
    db.session.commit()
    flash("文章已删除。")
    return redirect(url_for("index"))

4. URL 反向生成

4.1 url_for 函数

from flask import url_for, redirect

@app.route("/")
def index():
    return "首页"

@app.route("/user/<name>")
def user_profile(name):
    return f"用户:{name}"

@app.route("/articles")
def article_list():
    return "文章列表"

# 在模板中使用:
# {{ url_for('index') }}                    → /
# {{ url_for('user_profile', name='alice') }} → /user/alice
# {{ url_for('article_list') }}            → /articles

# 在代码中使用:
@app.route("/goto")
def goto():
    return redirect(url_for("article_list"))

4.2 url_for 的优势

# ❌ 硬编码 URL:改路由时要改所有引用
"<a href='/user/alice'>Alice</a>"
redirect("/user/alice")

# ✅ url_for:改路由后自动更新
"<a href='{{ url_for('user_profile', name='alice') }}'>Alice</a>"
redirect(url_for("user_profile", name="alice"))

5. 唯一 URL / 尾部斜杠

5.1 Flask 的智能重定向

@app.route("/about")
def about():
    return "关于页面"

# 访问 /about/ → Flask 自动重定向到 /about
# 访问 /about → 返回 "关于页面"

5.2 强制无尾部斜杠

@app.route("/contact", redirect_to=None)  # 默认行为:允许重定向

# 或者明确不允许尾部斜杠
@app.route("/items")
def items():
    # 访问 /items/ 会 404
    return "物品列表"

6. 路由蓝图模块化

# app/routes/main.py
from flask import Blueprint

main_bp = Blueprint("main", __name__)

@main_bp.route("/")
def index():
    return render_template("index.html")

@main_bp.route("/about")
def about():
    return render_template("about.html")

# app/__init__.py
from app.routes.main import main_bp
app.register_blueprint(main_bp)

7. 小结

# 路由速查

# 基本路由
@app.route("/path")
def handler():
    ...

# 变量路由
@app.route("/user/<name>")
@app.route("/post/<int:post_id>")

# 多方法
@app.route("/login", methods=["GET", "POST"])

# 反向生成
url_for("handler_name", arg=value)

# 蓝图
bp = Blueprint("name", __name__)
app.register_blueprint(bp, url_prefix="/prefix")

💡 设计原则:URL 应该描述资源而非操作。好 URL:/articles/42/editGET /articles/42 + PUT /articles/42


🔗 扩展阅读