FastAPI对接MongoDB返回用户列表时触发Pydantic校验错误求助
问题背景
基于MongoDB与FastAPI搭建服务时,开发全量用户查询接口,返回多条文档即触发报错,查阅多份资料未定位根因,相关代码、存储数据样例、报错信息如下。
关联代码与数据
models.py
from pydantic import BaseModel, constr, Field #Class for a user class User(BaseModel): username: constr(to_lower=True) _id: str = Field(..., alias='id') name: str isActive : bool weekPlan : str #Example to provide on FastAPI Docs class Config: allow_population_by_field_name = True orm_mode = True schema_extra = { "example": { "name": "John Smith", "username": "john@smith.com", "isActive": "true", "weekPlan": "1234567", } }
routes.py
from fastapi import APIRouter, HTTPException, status, Response from models.user import User from config.db import dbusers user = APIRouter() @user.get('/users', tags=["users"], response_model=list[User]) async def find_all_users(response: Response): # Content-Range needed for react-admin response.headers['Content-Range'] = '4' response.headers['Access-Control-Expose-Headers'] = 'content-range' users = (dbusers.find()) return users
MongoDB存储数据样例
{ "_id" : ObjectId("62b325f65402e5ceea8a4b6f") }, "name": "John Smith", "isActive" : true, "weekPlan" : "1234567" }, { "_id" : ObjectId("62b325f65402e5ceea9a3d4c"), "username" : "john@smith.com", "name" : "John Smith", "isActive" : true, "weekPlan" : "1234567" }
报错信息
await self.app(scope, receive, send) File "C:\Git2\thrive-app-react\backend\venv\lib\site-packages\starlette\routing.py", line 670, in __call__ await route.handle(scope, receive, send) File "C:\Git2\thrive-app-react\backend\venv\lib\site-packages\starlette\routing.py", line 266, in handle await self.app(scope, receive, send) File "C:\Git2\thrive-app-react\backend\venv\lib\site-packages\starlette\routing.py", line 65, in app response = await func(request) File "C:\Git2\thrive-app-react\backend\venv\lib\site-packages\fastapi\routing.py", line 235, in app response_data = await serialize_response( File "C:\Git2\thrive-app-react\backend\venv\lib\site-packages\fastapi\routing.py", line 138, in serialize_response raise ValidationError(errors, field.type_) pydantic.error_wrappers.ValidationError: 1 validation error for User response value is not a valid list (type=type_error.list)
问题根因
- 核心触发点:
dbusers.find()返回的是MongoDB的游标(Cursor)可迭代对象,不是Python原生列表类型,FastAPI做响应序列化时,无法将游标匹配到接口声明的list[User]响应模型,直接抛出类型校验错误。 - 模型定义缩进错误:
Config类定义在User类外部,配置的allow_population_by_field_name、orm_mode等规则完全不生效,字段别名映射逻辑失效。 - 字段映射配置错误:MongoDB返回的主键字段名为
_id,代码中将字段别名设为id,和实际返回字段名不匹配;且MongoDB默认返回的_id是ObjectId类型,不是字符串,Pydantic无法直接做类型转换。 - 脏数据问题:样例中第一条用户文档缺失必填的
username字段,即使类型问题修复,查询到该条数据时仍会触发字段校验错误。 - 响应头格式错误:
Content-Range头赋值为'4'不符合HTTP规范,react-admin无法正确解析,标准格式应为items 起始索引-结束索引/总条数。 - 示例值错误:模型
schema_extra中isActive字段写为字符串"true",和声明的bool类型冲突,会导致接口文档示例展示异常。
修复方案
- 修正
models.py代码,调整缩进将Config类放入User类内部,新增ObjectId类型转换逻辑,修正字段映射与示例值:
from pydantic import BaseModel, constr, Field from bson import ObjectId # 自定义MongoDB ObjectId类型校验,自动转成字符串 class PyObjectId(str): @classmethod def __get_validators__(cls): yield cls.validate @classmethod def validate(cls, v): if not isinstance(v, ObjectId): raise TypeError("must be a valid ObjectId") return str(v) class User(BaseModel): username: constr(to_lower=True) id: PyObjectId = Field(..., alias="_id") name: str isActive: bool weekPlan: str class Config: allow_population_by_field_name = True orm_mode = True schema_extra = { "example": { "name": "John Smith", "username": "john@smith.com", "isActive": True, "weekPlan": "1234567", } }
- 修正
routes.py逻辑,将MongoDB游标转为原生列表,按照规范设置Content-Range响应头:
from fastapi import APIRouter, Response from models.user import User from config.db import dbusers user = APIRouter() @user.get('/users', tags=["users"], response_model=list[User]) async def find_all_users(response: Response): # 将游标转为原生Python列表 users = list(dbusers.find()) total = len(users) # 按照规范设置Content-Range头 response.headers['Content-Range'] = f'items 0-{total-1}/{total}' response.headers['Access-Control-Expose-Headers'] = 'content-range' return users
- 清理MongoDB中的脏数据,为缺失
username字段的用户文档补全对应字段值,避免必填字段缺失触发校验错误。
内容的提问来源于stack exchange,提问作者Chris Taverner
相关产品推荐
相关产品推荐

