fastapi(65)- 路由函数指定了 response_model,在返回自定义 JSONResponse 时, 不会限制它返回的数据结构
前置知识
JSONResponse:https://www.cnblogs.com/poloyy/p/15364445.html
response_model:https://www.cnblogs.com/poloyy/p/15317585.html
背景
在写辣鸡平台,然后有统一的自定义 JSONResponse,所以全部路径函数都是返回自定义 JSONResponse 的,比如
@router.post("/save", response_model=UserResponse) async def save(user_save: UserSave, db: Session = Depends(get_db)) -> JSONResponse: ... return SuccessResponse(message="123", data=123) @router.post("/user_list", response_model=UserListResponse) async def get_user_list( user_page: UserPage, db: Session = Depends(get_db) ) -> JSONResponse: ... return SuccessResponse(data=123) @router.put("/active", response_model=BaseResponse) async def active( id: int = Body(..., description="用户ID"), state: States = Body(default=States.ACTIVE, description="用户状态"), db: Session = Depends(get_db), ) -> JSONResponse: ... return SuccessResponse(message="123", data=123)
- 这里的 SuccessResponse 就是继承 JSONResponse,是一个自定义响应对象
- 然后也可以看到三个路径函数都指定了 response_model
问题来了
路由操作函数返回的是自定义 JSONResponse,同时指定了 response_model,按道理最后返回的响应数据应该被限制为 model 里面的数据才对,但实际并没有
为啥我会发现这个问题呢
- 在我创建 user 之后,想返回整个 user 对象给前端,但自然而然 password 是不可以返回的,所以 response_model 就去掉这个 password 字段
- 但最终返回的响应体仍然有 password 字段
重新演示一遍上述问题现象
fastapi 代码
from fastapi import FastAPI import uvicorn app = FastAPI() class UserBase(BaseModel): username: str email: str class UserCreate(UserBase): password: str fake_db = [] # response_model 的 UserBase 只包含 username、email 没有 password @app.post("/create", response_model=UserBase) async def create(user: UserCreate): # 模拟:添加数据进数据库 fake_db.append(user) # 模拟拿到完整的 user user = jsonable_encoder(user) return JSONResponse(status_code=200, content=user) if __name__ == "__main__": uvicorn.run("test:app", port=8001, debug=True)
查看 OpenAPI 文档
因为添加了 response_model,所以 Responses 的 Example Value 是按照 response_model 的数据来生成的,就没有 password
发起请求,查看响应
但真实发送请求后,还是有 password 字段
return 字典代替 JSONResponse
@app.post("/create", response_model=UserBase) async def create(user: UserCreate): # 模拟:添加数据进数据库 fake_db.append(user) # 模拟拿到完整的 user user = jsonable_encoder(user) return user
再发起请求,查看响应
假设最终 return 的是一个字典,那么 response_model 就可以限制它的响应数据了,所以这里没有 password
根本原因
首先要记得 response_model 的作用
- 将输出数据转换为 Model 中声明的类型
- 验证数据
- 在 OpenAPI 给 Response 添加 JSON Schema 和 Example Value
- 最重要:将输出数据限制为 model 的数据
再来,在 return 那打个断点,Debug 分别看看两种 return 的场景
return user 断点
- 断点后 F7 进入的就是这里
- 在经过 fastapi 内部一长串各种调用处理后,response 本身包含 password 字段,但最后得到的 response_data 已经去掉了 password 字段
- 得到这个 response_data 后,最后还是会将它赋值给 JSONResponse 的 content ,然后接口再返回给前端
return JSONResponse 断点
- 断点后 F7 进入的就是这里
- 和上面完全不一样,跳过了前面 fastapi 处理数据的一长串步骤
- 因为这里是直接 return JSONResponse,所以 content 值已经确定了
- 最后赋什么值,接口返回的就是什么,并不会受 response_model 的限制
那 return JSONResponse 还有必要设置 response_model 吗?
- 如果是合作开发,还是有必要的,因为 response_model 可以自动添加 JSON Schema、Example Value 在 Swagger 文档中,可读性大大提升
- 但它的作用也仅是提供 JSON Schema、Example Value
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2020-11-13 Docker 实战(3)- 搭建 Gitlab 容器并上传本地项目代码
2020-11-13 Docker - 解决 gitlab 容器上的项目进行 clone 时,IP 地址显示一串数字而不是正常 IP 地址的问题
2020-11-13 Docker - 解决同步容器与主机时间报错:Error response from daemon: Error processing tar file(exit status 1): invalid symlink "/usr/share/zoneinfo/UTC" -> "../usr/share/zoneinfo/Asia/Shanghai"
2020-11-13 Docker - 解决容器内获取的时间和主机的时间不一样的问题