← 返回首页
🍶

Flask框架基础:路由、模板、请求响应与蓝图

📂 python ⏱ 5 min 852 words

Flask框架基础:路由、模板、请求响应与蓝图

Flask是一个轻量级的Python Web框架,被称为"微框架"。它核心简单但可扩展性强,非常适合快速开发Web应用和API。本文将带你掌握Flask的基础知识。

安装Flask

pip install flask

最简单的Flask应用

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello, Flask!"

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

路由系统

Flask的路由系统支持多种参数和HTTP方法:

from flask import Flask

app = Flask(__name__)

# 基本路由
@app.route("/")
def index():
    return "首页"

# 带参数的路由
@app.route("/user/<username>")
def user_profile(username):
    return f"用户: {username}"

# 多种类型转换器
@app.route("/post/<int:post_id>")
def post_detail(post_id):
    return f"文章ID: {post_id}"

@app.route("/float/<float:number>")
def show_number(number):
    return f"数字: {number}"

@app.route("/path/<path:subpath>")
def show_subpath(subpath):
    return f"子路径: {subpath}"

# 指定HTTP方法
@app.route("/users", methods=["GET", "POST"])
def users():
    from flask import request
    if request.method == "POST":
        return "创建用户"
    return "用户列表"

# URL构建
from flask import url_for

@app.route("/link")
def link():
    # 使用url_for生成URL
    url = url_for("user_profile", username="zhangsan")
    return f"用户链接: {url}"

# 多个URL规则
@app.route("/home")
@app.route("/")
def home():
    return "欢迎回家"

请求与响应

Flask提供了丰富的请求和响应处理功能:

from flask import Flask, request, make_response, jsonify, redirect, abort

app = Flask(__name__)

@app.route("/request-info")
def request_info():
    """获取请求信息"""
    info = {
        "method": request.method,
        "url": request.url,
        "path": request.path,
        "args": request.args.to_dict(),  # 查询参数
        "form": request.form.to_dict(),  # 表单数据
        "json": request.get_json(silent=True),  # JSON数据
        "headers": dict(request.headers),
        "remote_addr": request.remote_addr,
        "user_agent": request.user_agent.string
    }
    return jsonify(info)

@app.route("/login", methods=["POST"])
def login():
    """处理登录"""
    username = request.form.get("username")
    password = request.form.get("password")
    
    if username == "admin" and password == "123456":
        return jsonify({"message": "登录成功", "token": "abc123"})
    return jsonify({"error": "用户名或密码错误"}), 401

@app.route("/json-api", methods=["POST"])
def json_api():
    """处理JSON请求"""
    data = request.get_json()
    if not data:
        return jsonify({"error": "无效的JSON"}), 400
    
    return jsonify({"received": data})

@app.route("/custom-response")
def custom_response():
    """自定义响应"""
    response = make_response(jsonify({"message": "自定义响应"}), 200)
    response.headers["X-Custom-Header"] = "value"
    response.set_cookie("session", "abc123", max_age=3600)
    return response

@app.route("/redirect-example")
def redirect_example():
    """重定向"""
    return redirect(url_for("index"))

@app.route("/forbidden")
def forbidden():
    """错误处理"""
    abort(403)

模板渲染

Flask使用Jinja2模板引擎:

from flask import Flask, render_template

app = Flask(__name__)

@app.route("/user/<username>")
def user_profile(username):
    user = {
        "name": username,
        "age": 25,
        "hobbies": ["编程", "阅读", "游泳"]
    }
    return render_template("profile.html", user=user, title="用户主页")
<!-- templates/profile.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ user.name }}的主页</h1>
    <p>年龄: {{ user.age }}</p>
    
    <!-- 条件判断 -->
    {% if user.age >= 18 %}
        <p>已成年</p>
    {% else %}
        <p>未成年</p>
    {% endif %}
    
    <!-- 循环 -->
    <h3>兴趣爱好:</h3>
    <ul>
        {% for hobby in user.hobbies %}
            <li>{{ hobby }}</li>
        {% endfor %}
    </ul>
    
    <!-- 过滤器 -->
    <p>大写: {{ user.name|upper }}</p>
    <p>默认值: {{ user.email|default('未设置') }}</p>
    
    <!-- 模板继承 -->
    {% extends "base.html" %}
    {% block content %}
        <p>页面内容</p>
    {% endblock %}
    
    <!-- 包含模板 -->
    {% include "sidebar.html" %}
</body>
</html>

静态文件

from flask import Flask, send_from_directory

app = Flask(__name__)

@app.route("/static/<path:filename>")
def static_files(filename):
    return send_from_directory("static", filename)
<!-- 在模板中引用静态文件 -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<img src="{{ url_for('static', filename='images/logo.png') }}">

会话与Cookie

from flask import Flask, session, make_response

app = Flask(__name__)
app.secret_key = "your-secret-key-here"

@app.route("/set-session")
def set_session():
    """设置会话"""
    session["username"] = "admin"
    session["logged_in"] = True
    return "会话已设置"

@app.route("/get-session")
def get_session():
    """获取会话"""
    username = session.get("username", "未登录")
    return f"当前用户: {username}"

@app.route("/clear-session")
def clear_session():
    """清除会话"""
    session.clear()
    return "会话已清除"

@app.route("/set-cookie")
def set_cookie():
    """设置Cookie"""
    response = make_response("Cookie已设置")
    response.set_cookie("theme", "dark", max_age=86400)
    return response

@app.route("/get-cookie")
def get_cookie():
    """获取Cookie"""
    from flask import request
    theme = request.cookies.get("theme", "light")
    return f"当前主题: {theme}"

蓝图(Blueprint)

蓝图用于组织大型应用:

from flask import Blueprint, jsonify

# 创建蓝图
api = Blueprint("api", __name__, url_prefix="/api")

@api.route("/users")
def get_users():
    return jsonify([{"id": 1, "name": "张三"}])

@api.route("/users/<int:user_id>")
def get_user(user_id):
    return jsonify({"id": user_id, "name": "张三"})

@api.route("/users", methods=["POST"])
def create_user():
    from flask import request
    data = request.get_json()
    return jsonify(data), 201

# 在应用中注册蓝图
from flask import Flask
app = Flask(__name__)
app.register_blueprint(api)

项目结构

myapp/
├── app.py
├── config.py
├── requirements.txt
├── static/
│   ├── css/
│   ├── js/
│   └── images/
├── templates/
│   ├── base.html
│   └── index.html
└── blueprints/
    ├── __init__.py
    ├── auth.py
    └── api.py
# blueprints/auth.py
from flask import Blueprint, render_template, request, redirect, url_for, session

auth = Blueprint("auth", __name__)

@auth.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        username = request.form.get("username")
        password = request.form.get("password")
        
        # 验证逻辑
        if username == "admin" and password == "123456":
            session["user"] = username
            return redirect(url_for("main.index"))
        return render_template("login.html", error="用户名或密码错误")
    return render_template("login.html")

@auth.route("/logout")
def logout():
    session.pop("user", None)
    return redirect(url_for("auth.login"))

# app.py中注册
from blueprints.auth import auth
app.register_blueprint(auth)

错误处理

from flask import Flask, jsonify

app = Flask(__name__)

@app.errorhandler(404)
def not_found(error):
    return jsonify({"error": "资源不存在"}), 404

@app.errorhandler(500)
def server_error(error):
    return jsonify({"error": "服务器内部错误"}), 500

@app.errorhandler(403)
def forbidden(error):
    return jsonify({"error": "禁止访问"}), 403

# 自定义异常
class APIError(Exception):
    def __init__(self, message, status_code=400):
        self.message = message
        self.status_code = status_code

@app.errorhandler(APIError)
def handle_api_error(error):
    return jsonify({"error": error.message}), error.status_code

@app.route("/raise-error")
def raise_error():
    raise APIError("自定义错误", 400)

配置管理

# config.py
class Config:
    SECRET_KEY = "dev-secret-key"
    DEBUG = False
    DATABASE_URI = "sqlite:///app.db"

class DevelopmentConfig(Config):
    DEBUG = True
    DATABASE_URI = "sqlite:///dev.db"

class ProductionConfig(Config):
    SECRET_KEY = "production-secret-key"
    DATABASE_URI = "mysql://user:pass@localhost/prod"

class TestingConfig(Config):
    TESTING = True
    DATABASE_URI = "sqlite:///:memory:"

# app.py
from flask import Flask
from config import DevelopmentConfig

def create_app(config_class=DevelopmentConfig):
    app = Flask(__name__)
    app.config.from_object(config_class)
    
    # 注册蓝图
    from blueprints.api import api
    app.register_blueprint(api)
    
    return app

实战示例:Todo应用

from flask import Flask, render_template, request, jsonify, redirect, url_for
import json

app = Flask(__name__)
app.secret_key = "todo-secret-key"

# 简单的内存存储
todos = []
next_id = 1

@app.route("/")
def index():
    return render_template("todos.html", todos=todos)

@app.route("/todos", methods=["GET"])
def get_todos():
    return jsonify(todos)

@app.route("/todos", methods=["POST"])
def add_todo():
    global next_id
    title = request.json.get("title")
    if not title:
        return jsonify({"error": "标题不能为空"}), 400
    
    todo = {"id": next_id, "title": title, "done": False}
    todos.append(todo)
    next_id += 1
    return jsonify(todo), 201

@app.route("/todos/<int:todo_id>", methods=["PUT"])
def update_todo(todo_id):
    todo = next((t for t in todos if t["id"] == todo_id), None)
    if not todo:
        return jsonify({"error": "Todo不存在"}), 404
    
    data = request.json
    todo["title"] = data.get("title", todo["title"])
    todo["done"] = data.get("done", todo["done"])
    return jsonify(todo)

@app.route("/todos/<int:todo_id>", methods=["DELETE"])
def delete_todo(todo_id):
    global todos
    todos = [t for t in todos if t["id"] != todo_id]
    return jsonify({"message": "已删除"})

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

总结

Flask是学习Python Web开发的最佳起点。掌握路由、模板、请求响应、蓝图等基础概念后,你可以构建各种Web应用。下一步建议学习Flask进阶内容,如RESTful API、数据库集成、用户认证等。