Flask框架基础:路由、模板、请求响应与蓝图
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、数据库集成、用户认证等。