FastAPI定义Pydantic嵌套列表响应模型返回空的解决方法
问题描述
我尝试为嵌套字典列表结构的数据,在FastAPI中使用Pydantic模型构建response_model,但目前遇到无法解决的问题:只要在路由上添加response_model=配置,API返回的数据就为空;如果移除response_model=配置,相同的API请求可以正常返回包含完整内容的数据。
接口返回的数据结构如下:
[ { 'code': 'trabant', 'description': 'East German Trabant', 'listings': [ { id: 1000, cat_no: "Trabi1", descript: "Trabant Interior Mirror", price: Decimal(16.95), veh: 'trabant', sec: 'interior' }, { id: 1001, cat_no: "Trabi2", descript: "Trabant Interior Clock", price: Decimal(56.95), veh: 'trabant', sec: 'interior' } ] }, { 'code': 'skoda', 'description': 'Czech Skoda', 'listings': [ { id: 2001, cat_no: "Skoda5", descript: "Front Grille", price: Decimal(36.95), veh: 'skoda', sec: 'bodywork' }, { id: 2002, cat_no: "Skoda6", descript: "Skoda Grille Badge - Front", price: Decimal(16.95), veh: 'skoda', sec: 'bodywork' } ] } ]
提炼后的核心结构如下:
# 根节点为列表 [ { # 列表可包含40+种任意车辆数据 'code': str, # 车辆数据库编码 'description': str, # 车辆文本名称 'listings': [ # 当前车辆对应的配件目录条目列表 { id: int, # 数据库ID cat_no: str, # 客户SKU descript: str, # 配件描述 price: Decimal, # 价格Decimal类型值,不使用浮点数 veh: str, # 车辆数据库编码 sec: str # 分区数据库编码 } ] } ]
我尝试使用如下Pydantic模型描述该结构:
class ORMBaseModel(BaseModel): class Config: orm_mode = True class CatListing(ORMBaseModel): id: int cat_no: str descript: str sec: str veh: str price: Decimal class VehicleCatListings(ORMBaseModel): code: str description: str listings: List[CatListing] class ListOfCatListings(ORMBaseModel): List[VehicleCatListings]
但当我使用如下路由配置时:
@app.get("/api/cat_no/{ff_no}/listings", response_model=schema.ListOfCatListings) def getListings(ff_no: str, db: Session = Depends(databases.getDb)): listings = crud.catalogue.getListings(db, ff_no) # 数据库请求,返回上述结构的数据 if listings is None: raise HTTPException(status_code=404, detail="FF No catalogue listings not found") return listings
接口仅返回空对象{},仿佛Pydantic模型以某种方式忽略了传入数据,目前该问题调试难度较大。
注:我并不在销售稀有东欧汽车配件的公司工作,上述内容仅为示例 ;)
问题原因
返回空对象的核心原因是根响应模型定义错误:
接口根返回值是列表类型,但定义的ListOfCatListings是继承自BaseModel的普通对象模型,类体内仅写了List[VehicleCatListings]没有绑定到任何声明字段,Pydantic会将其识别为无字段的空模型,序列化后自然返回空对象{}。
修复方案
不需要额外定义包裹用的ListOfCatListings类,直接在路由的response_model中声明列表类型即可:
- 移除无效的
ListOfCatListings类定义 - 修改路由装饰器的
response_model参数为List[schema.VehicleCatListings]
修正后的路由代码:
from typing import List # CatListing、VehicleCatListings模型保持原有定义即可,无需修改 @app.get("/api/cat_no/{ff_no}/listings", response_model=List[schema.VehicleCatListings]) def getListings(ff_no: str, db: Session = Depends(databases.getDb)): listings = crud.catalogue.getListings(db, ff_no) if listings is None: raise HTTPException(status_code=404, detail="FF No catalogue listings not found") return listings
如果需要显式定义根列表类型,Pydantic V2版本可使用RootModel实现,写法如下:
from pydantic import RootModel class ListOfCatListings(RootModel[List[VehicleCatListings]]): pass
该写法同样可以正确识别根节点为列表结构,不会返回空对象。
另外注意示例数据中部分字典条目缺少逗号分隔,实际业务代码中需保证语法正确,避免序列化报错。
内容的提问来源于stack exchange,提问作者MarkBenson
相关产品推荐
相关产品推荐

