强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

18 - Web 开发

第 18 章:Web 开发

掌握 FastAPI、Flask、Django 等主流 Web 框架的核心概念。


18.1 Python Web 框架对比

框架类型特点适用场景
FastAPI异步类型驱动、自动文档、高性能API 服务、微服务
Flask同步轻量灵活、扩展丰富小型应用、原型
Django同步全功能、ORM、Admin大型应用、CMS

18.2 FastAPI

18.2.1 基本示例

from fastapi import FastAPI

app = FastAPI(title="My API", version="1.0.0")

@app.get("/")
async def root():
    return {"message": "Hello, World!"}

@app.get("/items/{item_id}")
async def get_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}
$ pip install fastapi uvicorn
$ uvicorn main:app --reload
# 访问 http://localhost:8000/docs 查看自动文档

18.2.2 请求体与验证

from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class Item(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    price: float = Field(..., gt=0)
    description: str | None = None
    tags: list[str] = []

@app.post("/items/", status_code=201)
async def create_item(item: Item):
    return {"id": 1, **item.model_dump()}

@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    return {"item_id": item_id, **item.model_dump()}

18.2.3 路由组织

from fastapi import APIRouter

router = APIRouter(prefix="/api/users", tags=["users"])

@router.get("/")
async def list_users():
    return [{"id": 1, "name": "Alice"}]

@router.get("/{user_id}")
async def get_user(user_id: int):
    return {"id": user_id, "name": "Alice"}

# main.py
app = FastAPI()
app.include_router(router)

18.2.4 依赖注入

from fastapi import Depends, FastAPI, HTTPException, Header

app = FastAPI()

async def get_token_header(authorization: str = Header()):
    if not authorization.startswith("Bearer "):
        raise HTTPException(status_code=401, detail="Invalid token")
    return authorization[7:]

async def get_current_user(token: str = Depends(get_token_header)):
    # 验证 token 并返回用户
    return {"id": 1, "name": "Alice"}

@app.get("/me")
async def read_me(user: dict = Depends(get_current_user)):
    return user

18.2.5 中间件

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import time

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.middleware("http")
async def add_process_time_header(request, call_next):
    start = time.perf_counter()
    response = await call_next(request)
    process_time = time.perf_counter() - start
    response.headers["X-Process-Time"] = str(process_time)
    return response

18.3 Flask

18.3.1 基本示例

from flask import Flask, jsonify, request

app = Flask(__name__)

@app.route("/")
def index():
    return jsonify(message="Hello, World!")

@app.route("/items/<int:item_id>")
def get_item(item_id):
    q = request.args.get("q")
    return jsonify(item_id=item_id, q=q)

@app.route("/items", methods=["POST"])
def create_item():
    data = request.get_json()
    return jsonify(data), 201

if __name__ == "__main__":
    app.run(debug=True)
$ pip install flask
$ flask --app main run

18.3.2 Blueprint(蓝图)

from flask import Blueprint, jsonify

users_bp = Blueprint("users", __name__, url_prefix="/api/users")

@users_bp.route("/")
def list_users():
    return jsonify(users=[{"id": 1, "name": "Alice"}])

# app.py
from flask import Flask

app = Flask(__name__)
app.register_blueprint(users_bp)

18.4 Django

18.4.1 项目结构

mysite/
├── manage.py
├── mysite/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── users/
    ├── __init__.py
    ├── models.py
    ├── views.py
    ├── urls.py
    └── serializers.py

18.4.2 模型

from django.db import models

class User(models.Model):
    name = models.CharField(max_length=100)
    email = models.EmailField(unique=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return self.name

18.4.3 视图

from django.http import JsonResponse
from django.views import View

class UserView(View):
    def get(self, request):
        users = list(User.objects.values("id", "name", "email"))
        return JsonResponse({"users": users})

    def post(self, request):
        data = json.loads(request.body)
        user = User.objects.create(**data)
        return JsonResponse({"id": user.id}, status=201)

18.5 REST API 设计

方法路径动作状态码
GET/items获取列表200
GET/items/{id}获取单个200 / 404
POST/items创建201
PUT/items/{id}全量更新200 / 404
PATCH/items/{id}部分更新200 / 404
DELETE/items/{id}删除204 / 404

18.6 模板渲染

Jinja2(Flask/FastAPI)

from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates

app = FastAPI()
templates = Jinja2Templates(directory="templates")

@app.get("/")
async def index(request: Request):
    return templates.TemplateResponse("index.html", {
        "request": request,
        "title": "首页",
        "items": ["Python", "FastAPI", "Docker"],
    })
<!-- templates/index.html -->
<h1>{{ title }}</h1>
<ul>
{% for item in items %}
    <li>{{ item }}</li>
{% endfor %}
</ul>

18.7 注意事项

🔴 注意

  • 不要在生产环境使用 Flask/FastAPI 的开发服务器
  • 始终验证和过滤用户输入
  • 使用 gunicornuvicorn 部署
  • 敏感配置使用环境变量,不要硬编码

💡 提示

  • API 服务首选 FastAPI(自动文档、类型验证)
  • 全功能 Web 应用首选 Django
  • 轻量应用或微服务用 Flask
  • 使用 Pydantic 做数据验证

📌 业务场景

from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
from sqlalchemy.orm import Session

app = FastAPI()

class UserCreate(BaseModel):
    name: str
    email: str

class UserResponse(BaseModel):
    id: int
    name: str
    email: str

@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate, db: Session = Depends(get_db)):
    db_user = db.query(User).filter(User.email == user.email).first()
    if db_user:
        raise HTTPException(status_code=400, detail="邮箱已注册")
    new_user = User(**user.model_dump())
    db.add(new_user)
    db.commit()
    db.refresh(new_user)
    return new_user

18.8 扩展阅读