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

Python 编程教程 / 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 扩展阅读