4. 响应模型与数据过滤
任务说明
本案例要求为FastAPI接口定义明确的响应模型,实现两个目标:一是隐藏敏感字段(如密码、内部ID),二是按需控制输出字段。我们将通过一个用户信息查询接口演示Pydantic响应模型的核心用法。
核心实现
# main.py
from typing import Optional
from fastapi import FastAPI, Query
from pydantic import BaseModel, EmailStr, Field
app = FastAPI()
# ---------- 内部数据模型(含敏感字段) ----------
class UserInDB(BaseModel):
user_id: int
username: str
email: EmailStr
hashed_password: str = Field(..., description="内部使用,绝不返回")
is_active: bool = True
secret_note: Optional[str] = None # 内部备注,不对外暴露
# ---------- 对外响应模型(安全字段) ----------
class UserPublic(BaseModel):
username: str
email: EmailStr
is_active: bool
# ---------- 带字段控制的响应模型 ----------
class UserProfile(UserPublic):
user_id: int # 仅当请求方需要时通过参数控制返回
# ---------- 模拟数据库 ----------
fake_db = {
1: UserInDB(
user_id=1,
username="alice",
email="alice@example.com",
hashed_password="fakehash123",
secret_note="内部备注A",
),
2: UserInDB(
user_id=2,
username="bob",
email="bob@example.com",
hashed_password="fakehash456",
is_active=False,
),
}
# ---------- 接口1:自动过滤敏感字段 ----------
@app.get("/users/{user_id}", response_model=UserPublic)
def get_user(user_id: int):
"""返回用户公开信息,自动剔除 hashed_password 和 secret_note"""
if user_id not in fake_db:
return {"detail": "用户不存在"} # 实际应使用 HTTPException
return fake_db[user_id]
# ---------- 接口2:通过查询参数控制输出字段 ----------
@app.get("/users/{user_id}/profile", response_model=UserProfile)
def get_user_profile(
user_id: int,
include_id: bool = Query(False, description="是否返回 user_id 字段"),
):
"""根据 include_id 参数决定是否返回 user_id"""
if user_id not in fake_db:
return {"detail": "用户不存在"}
user = fake_db[user_id]
# 构造返回数据,仅包含 UserProfile 中定义的字段
result = {
"username": user.username,
"email": user.email,
"is_active": user.is_active,
}
if include_id:
result["user_id"] = user.user_id
return result
关键机制说明
上述代码通过三层模型实现字段控制:UserInDB代表数据库完整记录,包含hashed_password和secret_note等敏感字段;UserPublic作为对外响应模型,仅声明公开字段,FastAPI会自动将UserInDB实例转换为UserPublic结构,未声明的字段被丢弃;UserProfile继承自UserPublic并增加user_id,配合查询参数实现可选字段输出。接口2中手动构造字典是为了演示字段级控制逻辑——当include_id=False时,返回数据中不包含user_id键,FastAPI会按UserProfile模型校验并过滤。
运行与验证
# 安装依赖
pip install fastapi uvicorn pydantic[email]
# 启动服务
uvicorn main:app --reload --port 8000
启动后访问以下URL验证:
- 接口1:
GET http://127.0.0.1:8000/users/1— 预期返回JSON仅含username、email、is_active三个字段,无hashed_password和secret_note。 - 接口2(不带参数):
GET http://127.0.0.1:8000/users/1/profile— 预期返回不含user_id。 - 接口2(带参数):
GET http://127.0.0.1:8000/users/1/profile?include_id=true— 预期返回包含user_id字段。
判定标准:响应中绝不出现hashed_password或secret_note;接口2的返回字段随include_id参数正确变化;访问不存在的用户(如/users/999)时返回{"detail":"用户不存在"}。