2024 年的 Python Web 框架格局正在快速变化:FastAPI 以「类型驱动」和「原生异步」横扫 API 开发领域,Flask 凭借简洁守住中小型项目,Django 仍是全功能 CMS/Admin 的首选。本文从选型到部署,覆盖完整工程路径。
1. 三框架选型矩阵
| 维度 | FastAPI | Flask | Django |
|---|---|---|---|
| 学习曲线 | 中等(需理解类型系统) | 低 | 高(大而全) |
| 原生异步 | ✅ async/await | ❌ 需 extensions | ✅ Django 4.2+ |
| 自动生成文档 | ✅ OpenAPI/Swagger/ReDoc | ❌ 需手动 | ❌ 需 DRF |
| 数据验证 | ✅ Pydantic 集成 | ❌ 手动/WTForms | ✅ DRF Serializers |
| Admin 后台 | ❌ 需第三方 | ❌ | ✅ 内置 |
| ORM | SQLAlchemy/SQLModel | SQLAlchemy | ✅ Django ORM |
| 生态规模 | 快速增长(50k+ stars) | 成熟(70k+ stars) | 最大 |
| 适用场景 | API/微服务 | 小型 Web/API | CMS/电商/内容管理 |
2. FastAPI 核心实战
2.1 Hello World 到 CRUD
from fastapi import FastAPI, HTTPException, status
from pydantic import BaseModel
from typing import List
app = FastAPI(title="Task API", version="1.0.0")
class Task(BaseModel):
id: int
title: str
completed: bool = False
class Config:
json_schema_extra = {
"example": {
"id": 1,
"title": "Learn FastAPI",
"completed": False
}
}
# 内存存储(实际用数据库)
tasks_db: dict[int, Task] = {}
@app.get("/tasks", response_model=List[Task])
async def list_tasks():
return list(tasks_db.values())
@app.post("/tasks", response_model=Task, status_code=status.HTTP_201_CREATED)
async def create_task(task: Task):
if task.id in tasks_db:
raise HTTPException(status_code=400, detail="Task already exists")
tasks_db[task.id] = task
return task
@app.get("/tasks/{task_id}", response_model=Task)
async def get_task(task_id: int):
if task_id not in tasks_db:
raise HTTPException(status_code=404, detail="Task not found")
return tasks_db[task_id]
@app.put("/tasks/{task_id}", response_model=Task)
async def update_task(task_id: int, task: Task):
if task_id not in tasks_db:
raise HTTPException(status_code=404, detail="Task not found")
tasks_db[task_id] = task
return task
@app.delete("/tasks/{task_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_task(task_id: int):
if task_id not in tasks_db:
raise HTTPException(status_code=404, detail="Task not found")
del tasks_db[task_id]
启动服务:
pip install fastapi uvicorn
uvicorn main:app --reload
# 自动文档: http://localhost:8000/docs (Swagger)
# http://localhost:8000/redoc (ReDoc)
2.2 依赖注入(Dependency Injection)
FastAPI 的依赖注入是框架最具竞争力的特性之一:
from fastapi import Depends, HTTPException
from typing import Annotated
# 依赖函数
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
# 可复用的分页依赖
def pagination_params(
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100)
) -> PaginationParams:
return PaginationParams(page=page, page_size=page_size)
# 认证依赖
def get_current_user(token: str = Header(...)) -> User:
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
return User(id=payload["sub"], name=payload["name"])
except jwt.PyJWTError:
raise HTTPException(status_code=401, detail="Invalid token")
# 使用依赖
@app.get("/users/me")
async def read_users_me(
current_user: Annotated[User, Depends(get_current_user)]
):
return current_user
# 依赖嵌套
async def require_admin(
user: Annotated[User, Depends(get_current_user)]
) -> User:
if not user.is_admin:
raise HTTPException(status_code=403, detail="Admin required")
return user
依赖注入优势:
- 测试时可轻松 mock 依赖
- 数据库连接自动管理(
yield保证关闭) - 认证/授权逻辑与业务解耦
2.3 后台任务(Background Tasks)
from fastapi import BackgroundTasks
import asyncio
async def send_email(email: str, message: str):
await asyncio.sleep(2) # 模拟发送
print(f"Email sent to {email}: {message}")
@app.post("/signup")
async def signup(
user: UserCreate,
background_tasks: BackgroundTasks
):
# 同步响应(不等待邮件发送)
background_tasks.add_task(send_email, user.email, "Welcome!")
return {"message": "User registered"}
⚠️ 注意: BackgroundTasks 不适合长时间任务(>30s),应使用 Celery/RQ。
2.4 自定义中间件
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
import time
class TimingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
start = time.perf_counter()
response = await call_next(request)
duration = time.perf_counter() - start
response.headers["X-Response-Time"] = f"{duration:.3f}s"
return response
# 注册
app.add_middleware(TimingMiddleware)
# 另一个:CORS
from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(
CORSMiddleware,
allow_origins=["https://example.com"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
2.5 异常处理与统一响应
from fastapi import Request
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
class AppException(Exception):
def __init__(self, message: str, status_code: int = 400):
self.message = message
self.status_code = status_code
@app.exception_handler(AppException)
async def app_exception_handler(request: Request, exc: AppException):
return JSONResponse(
status_code=exc.status_code,
content={"success": False, "message": exc.message}
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
return JSONResponse(
status_code=422,
content={
"success": False,
"message": "Validation failed",
"errors": exc.errors()
}
)
# 统一响应模型
class APIResponse(BaseModel):
success: bool
data: Any = None
message: str | None = None
3. 数据库集成:SQLAlchemy + SQLModel
3.1 SQLModel(FastAPI 官方推荐)
SQLModel = SQLAlchemy + Pydantic,统一声明:
from sqlmodel import SQLModel, Field, create_engine, Session, select
from typing import Optional
class User(SQLModel, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
name: str = Field(index=True)
email: str = Field(unique=True, index=True)
is_active: bool = True
# 创建引擎
engine = create_engine("sqlite:///./app.db", echo=True)
SQLModel.metadata.create_all(engine)
# CRUD 操作
with Session(engine) as session:
# Create
user = User(name="Alice", email="alice@example.com")
session.add(user)
session.commit()
# Read
statement = select(User).where(User.name == "Alice")
alice = session.exec(statement).first()
# Update
alice.is_active = False
session.add(alice)
session.commit()
# Delete
session.delete(alice)
session.commit()
3.2 异步数据库(async SQLAlchemy)
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
# 使用 asyncpg(PostgreSQL)
engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
async def get_async_db():
async with async_session() as session:
yield session
@app.get("/users")
async def list_users(db: AsyncSession = Depends(get_async_db)):
result = await db.execute(select(User))
return result.scalars().all()
4. JWT 认证完整实现
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
def get_password_hash(password: str) -> str:
return pwd_context.hash(password)
def create_access_token(data: dict, expires_delta: timedelta | None = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
# OAuth2 密码流
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=401,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
except JWTError:
raise credentials_exception
user = get_user(username) # 从数据库获取
if user is None:
raise credentials_exception
return user
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=401, detail="Invalid credentials")
token = create_access_token(data={"sub": user.username})
return {"access_token": token, "token_type": "bearer"}
@app.get("/protected")
async def protected_route(current_user: User = Depends(get_current_user)):
return {"message": f"Hello, {current_user.username}!"}
5. 部署到生产
5.1 Docker 多阶段构建
# Build stage
FROM python:3.12-slim as builder
WORKDIR /app
RUN pip install --no-cache-dir poetry
COPY pyproject.toml poetry.lock ./
RUN poetry config virtualenvs.create false \
&& poetry install --no-dev
# Production stage
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
COPY ./app ./app
EXPOSE 8000
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
5.2 高性能部署:gunicorn + uvicorn workers
# 多 worker 模式(推荐)
gunicorn app.main:app \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000 \
--access-logfile - \
--error-logfile -
# 或使用 uvicorn 原生(单进程)
uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
Worker 数量公式:
workers = (2 × CPU cores) + 1
# 4 核 → 9 workers
# Gunicorn 管理进程 + Uvicorn Worker 处理请求
6. 性能基准
| 框架 | 延迟 (p99) | 吞吐量 (req/s) | 内存/1000 并发 |
|---|---|---|---|
| FastAPI + uvicorn | 12ms | 18,000 | 45MB |
| Flask + gunicorn | 28ms | 4,500 | 60MB |
| Django + gunicorn | 35ms | 3,200 | 85MB |
| Node.js + Express | 8ms | 25,000 | 40MB |
测试环境:AWS t3.medium, wrk -t12 -c1000 -d30s
延伸阅读
- Python 类型系统与 Pydantic — FastAPI 的类型基础
- Python 并发与性能 — 数据库连接池与异步
- Python 部署指南 — Docker 与 CI/CD 详解
- Node.js Express 对比 — JavaScript 后端选型参考
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。
「python」更多文章
Python 部署与分发:Docker、PyPI 发布与可复现环境
Python 项目从开发到生产的完整部署路径:Docker 多阶段构建与镜像优化、uvicorn/gunicorn 服务器配置、pyinstaller/uv 打包独立可执行文件、PyPI 包发布流程、Nix 可复现环境。附带 Dockerfile 模板和 GitHub Actions 发布流水线。
Python 测试与质量工程:pytest、mock 与覆盖率实战
Python 测试金字塔完整实践:pytest 核心(fixture/parametrize/monkeypatch)、unittest.mock/patch、Monkeypatch、覆盖率 pytest-cov、类型测试、CI 集成策略与 doctest。覆盖从单元测试到集成测试的完整工程方案。
Python 现代工具链:uv + ruff + mypy 全链路工程实践
Python 工具链现代化完整指南:uv(极速包管理+虚拟环境+Python 安装)、ruff(lint+format 一体化)、mypy/pyright 类型检查、pipx 工具安装、 hatch/poetry/pdm 项目管理、从 pip 到 uv 的迁移路径。附带 pyproject.toml 完整配置模板。