Web 框架是构建 Web 应用的基础工具,它们提供了处理 HTTP 请求、路由管理、模板渲染等核心功能。本章将介绍主流的 Python Web 框架,重点学习 Flask 和 FastAPI。
Web 框架是一个软件框架,用于简化 Web 应用程序、Web 服务和 Web 站点的开发。它提供了一套标准化的方法来构建和部署 Web 应用。
- 路由管理:将 URL 映射到处理函数
- 请求处理:解析 HTTP 请求参数
- 响应生成:生成 HTTP 响应
- 模板渲染:渲染 HTML 页面
- 数据库集成:提供数据库操作接口
- 安全防护:处理认证、授权、CSRF 等
| 框架 | 特点 | 适用场景 | 学习难度 |
|---|---|---|---|
| Flask | 轻量级、灵活 | 小型项目、原型开发 | 简单 |
| FastAPI | 现代、高性能、自动文档 | API 开发、微服务 | 中等 |
| Django | 全功能、企业级 | 大型项目、内容管理 | 复杂 |
| Tornado | 异步、高性能 | 实时应用、长连接 | 复杂 |
- 初学者:从 Flask 开始,学习基础概念
- API 开发:选择 FastAPI,享受现代特性
- 企业项目:考虑 Django,获得完整生态
- 高性能需求:评估 Tornado 或 FastAPI
# 安装 Flask
pip install flask
# 创建虚拟环境(推荐)
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windowsfrom flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def home():
return 'Hello, World!'
@app.route('/about')
def about():
return 'About Page'
@app.route('/api/users')
def get_users():
users = [
{'id': 1, 'name': '张三'},
{'id': 2, 'name': '李四'}
]
return jsonify(users)
@app.route('/user/<int:user_id>')
def get_user(user_id):
return f'User ID: {user_id}'
if __name__ == '__main__':
app.run(debug=True)# 基本路由
@app.route('/')
def index():
return 'Index Page'
# 带参数的路由
@app.route('/user/<username>')
def show_user(username):
return f'User: {username}'
# 指定 HTTP 方法
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
# 处理登录逻辑
return 'Login successful'
return render_template('login.html')
# 带类型转换的路由
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f'Post ID: {post_id}'from flask import request, jsonify, make_response
@app.route('/api/data', methods=['POST'])
def handle_data():
# 获取请求数据
data = request.get_json()
name = data.get('name', '')
# 处理数据
result = {'message': f'Hello, {name}!', 'status': 'success'}
# 返回 JSON 响应
return jsonify(result)
@app.route('/custom-response')
def custom_response():
response = make_response('Custom Response')
response.headers['Content-Type'] = 'text/plain'
response.status_code = 200
return responsefrom flask import render_template
@app.route('/profile/<username>')
def profile(username):
user_info = {
'name': username,
'email': f'{username}@example.com',
'age': 25
}
return render_template('profile.html', user=user_info)templates/profile.html:
<!DOCTYPE html>
<html>
<head>
<title>用户资料</title>
</head>
<body>
<h1>{{ user.name }} 的资料</h1>
<p>邮箱: {{ user.email }}</p>
<p>年龄: {{ user.age }}</p>
</body>
</html># 安装 FastAPI 和 ASGI 服务器
pip install fastapi uvicorn
# 安装可选依赖
pip install fastapi[all]from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Optional
app = FastAPI(title="My API", version="1.0.0")
# 数据模型
class User(BaseModel):
id: int
name: str
email: str
age: Optional[int] = None
class UserCreate(BaseModel):
name: str
email: str
age: Optional[int] = None
# 路由
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/users", response_model=List[User])
async def get_users():
users = [
User(id=1, name="张三", email="zhangsan@example.com", age=25),
User(id=2, name="李四", email="lisi@example.com", age=30)
]
return users
@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
# 模拟数据库查询
user = User(id=user_id, name="张三", email="zhangsan@example.com", age=25)
return user
@app.post("/users", response_model=User)
async def create_user(user: UserCreate):
# 模拟创建用户
new_user = User(id=3, **user.dict())
return new_user
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)from pydantic import BaseModel, EmailStr, validator
from typing import Optional
from datetime import datetime
class User(BaseModel):
id: int
name: str
email: EmailStr
age: Optional[int] = None
created_at: datetime = datetime.now()
@validator('age')
def validate_age(cls, v):
if v is not None and (v < 0 or v > 150):
raise ValueError('年龄必须在 0-150 之间')
return v
class Config:
schema_extra = {
"example": {
"id": 1,
"name": "张三",
"email": "zhangsan@example.com",
"age": 25
}
}from fastapi import Depends, HTTPException, status
from typing import Optional
# 模拟数据库
fake_users_db = {
"user1": {"username": "user1", "full_name": "User One"},
"user2": {"username": "user2", "full_name": "User Two"},
}
def get_user(username: str):
if username in fake_users_db:
return fake_users_db[username]
return None
@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_user)):
if current_user is None:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="User not found"
)
return current_userfrom fastapi import Request
import time
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
process_time = time.time() - start_time
response.headers["X-Process-Time"] = str(process_time)
return response
@app.exception_handler(404)
async def not_found_handler(request: Request, exc: HTTPException):
return {"message": "资源未找到", "path": request.url.path}| 特性 | Flask | FastAPI |
|---|---|---|
| 性能 | 中等 | 高性能 |
| 异步支持 | 有限 | 原生支持 |
| 自动文档 | 需要插件 | 内置 |
| 类型提示 | 可选 | 强制 |
| 学习曲线 | 简单 | 中等 |
| 生态系统 | 丰富 | 新兴 |
-
选择 Flask 的场景:
- 学习 Web 开发基础
- 快速原型开发
- 简单的 Web 应用
- 需要大量第三方扩展
-
选择 FastAPI 的场景:
- 构建现代 API
- 需要高性能
- 团队重视类型安全
- 需要自动生成文档
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
# 简单的内存存储
todos = []
@app.route('/')
def index():
return render_template('index.html', todos=todos)
@app.route('/add', methods=['POST'])
def add_todo():
todo = request.form.get('todo')
if todo:
todos.append({'id': len(todos) + 1, 'text': todo, 'done': False})
return redirect(url_for('index'))
@app.route('/toggle/<int:todo_id>')
def toggle_todo(todo_id):
for todo in todos:
if todo['id'] == todo_id:
todo['done'] = not todo['done']
break
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List, Optional
app = FastAPI()
class User(BaseModel):
id: int
name: str
email: str
class UserCreate(BaseModel):
name: str
email: str
# 模拟数据库
users_db = []
user_id_counter = 1
@app.post("/users", response_model=User)
async def create_user(user: UserCreate):
global user_id_counter
new_user = User(id=user_id_counter, **user.dict())
users_db.append(new_user)
user_id_counter += 1
return new_user
@app.get("/users", response_model=List[User])
async def get_users():
return users_db
@app.get("/users/{user_id}", response_model=User)
async def get_user(user_id: int):
for user in users_db:
if user.id == user_id:
return user
raise HTTPException(status_code=404, detail="User not found")完成本节学习后,请检查是否掌握:
- 理解 Web 框架的作用和特点
- 能够创建简单的 Flask 应用
- 掌握 Flask 的路由和视图函数
- 能够创建 FastAPI 应用
- 理解数据验证和依赖注入
- 能够选择合适的 Web 框架
上一节:1.1 HTTP 协议基础 | 下一节:1.3 前后端交互