FastAPI如何设置正确的response_model以返回MongoDB中的多条文档?
解决FastAPI + Motor-Asyncio使用Pydantic Response Model报错问题
问题原因分析
报错value is not a valid dict的核心原因:
ScoresOut模型要求返回包含result键的字典,但当前返回的是纯列表,格式不匹配- 模型中
historic_data字段名与MongoDB中的historical_data不一致,导致字段无法正确映射 - 查询投影未包含
historical_data,即使字段名修正,也无法返回该字段数据
具体解决方案
1. 修正Pydantic模型字段映射
修改ScoreOut模型,为字段添加别名匹配MongoDB结构,并开启别名填充支持:
from datetime import datetime from typing import List, Optional from pydantic import BaseModel, Field class ScoreOut(BaseModel): membershipNumber: str score: Optional[float] historic_data: Optional[list] = Field(None, alias="historical_data") # 映射Mongo的historical_data字段 created_at: Optional[datetime] region: Optional[str] district: Optional[str] branch: Optional[str] workplace: Optional[str] class Config: populate_by_name = True # 允许通过字段名或别名填充数据 class ScoresOut(BaseModel): result: List[ScoreOut]
2. 调整查询投影(按需返回字段)
如果需要返回historical_data字段,修改find的投影参数加入该字段:
c = coll.find( {'membershipNumber': {'$in': members}}, {'_id': 0, 'membershipNumber': 1, 'score': 1, 'workplace': 1, 'created_at': 1, 'historical_data': 1} )
3. 修正接口返回格式
将列表包装为符合ScoresOut结构的字典:
@ScoresRouter.get("/getScores") async def get_scores( members: Optional[list[str]] = Query(default=None), response_model=ScoresOut, response_model_exclude_unset=True ): c = coll.find( {'membershipNumber': {'$in': members}}, {'_id': 0, 'membershipNumber': 1, 'score': 1, 'workplace': 1, 'created_at': 1, 'historical_data': 1} ) out = [] async for doc in c: out.append(doc) # 返回符合ScoresOut结构的数据 return {"result": out} # 也可以直接返回模型实例:return ScoresOut(result=out)
额外说明
- Motor-Asyncio会自动将MongoDB的
ISODate转换为Python的datetime类型,Pydantic可直接解析,无需额外处理 response_model_exclude_unset=True会自动排除模型中未获取到值的字段(比如region、district等),精简返回数据
内容的提问来源于stack exchange,提问作者nikUoM
相关产品推荐
相关产品推荐

