FastAPI响应模型ValidationError问题:指定模型报错,移除则正常
问题描述
我在FastAPI中编写了如下接口:
@router.get("/",status_code=status.HTTP_200_OK,response_model= schemas.postout) def get_posts(db: session= Depends(get_db),current_user : int= Depends(oath2.get_current_user)): cursor.execute("select * from posts") posts=cursor.fetchall() returned_post= db.query(models.Post).all() return {'data': returned_post}
指定response_model为schemas.postout时出现验证错误,移除该参数后能正常返回字典格式响应。所用Pydantic模型定义:
class post(BaseModel): title: str content: str published: bool=True class Config: orm_mode= True class postout(post): id: int created_at: datetime creator_id: int class Config: orm_mode= True
收到的错误信息:
pydantic.error_wrappers.ValidationError: 5 validation errors for postout
response -> title field required (type=value_error.missing) response -> content field required (type=value_error.missing) response -> id field required (type=value_error.missing) response -> created_at field required (type=value_error.missing) response -> creator_id field required (type=value_error.missing)
移除响应模型后,正常返回的响应示例:
"data": [ { "published": true, "id": 8, "creator_id": 12, "title": "whatever I want2", "content": "Some cool stuff I wanted", "created_at": "2022-12-28T16:03:01.391997+00:00" }, { "published": true, "id": 14, "creator_id": 12, "title": "whatever I want2", "content": "Some cool stuff I wanted", "created_at": "2022-12-28T16:22:43.757510+00:00" } ]
原因分析
- 数据结构不匹配:接口返回的是
{'data': [帖子实例列表]}的嵌套结构,但指定的response_model=schemas.postout是单个帖子的模型。FastAPI会尝试把整个返回字典转换成postout对象,而字典中只有data键,没有postout要求的title、content等字段,因此触发缺失字段的验证错误。 - 模型类型不匹配:即使去掉外层
{'data': ...},直接返回帖子列表,也需要用List[schemas.postout]作为响应模型,而非单个postout。 - Pydantic模型缩进错误:原
post类的Config内部orm_mode未缩进,属于语法错误,会导致ORM模式不生效(不过这不是本次验证错误的直接原因,但需要修正)。
解决方案
方案一:创建匹配返回结构的Pydantic模型
定义一个包含data字段的顶层模型,字段类型为帖子模型的列表:
from pydantic import BaseModel from typing import List import schemas class PostResponse(BaseModel): data: List[schemas.postout] class Config: orm_mode = True
修改接口的response_model为这个新模型,同时删除冗余的原生SQL查询代码:
@router.get("/", status_code=status.HTTP_200_OK, response_model=schemas.PostResponse) def get_posts(db: session= Depends(get_db), current_user : int= Depends(oath2.get_current_user)): returned_post = db.query(models.Post).all() return {'data': returned_post}
方案二:直接返回帖子列表,调整响应模型
如果不需要外层data键,直接返回帖子列表,同时修改response_model为列表类型:
from typing import List @router.get("/", status_code=status.HTTP_200_OK, response_model=List[schemas.postout]) def get_posts(db: session= Depends(get_db), current_user : int= Depends(oath2.get_current_user)): returned_post = db.query(models.Post).all() return returned_post
额外修正:修复Pydantic模型缩进错误
原post类的Config内部代码需缩进,确保ORM模式生效:
class post(BaseModel): title: str content: str published: bool=True class Config: orm_mode= True # 此处需缩进,属于Config类的成员
内容的提问来源于stack exchange,提问作者C A OB1
相关产品推荐
相关产品推荐

