You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI结合SQLModel全局查询出现ResponseValidationError问题求助

问题:FastAPI + SQLModel 查询返回数据无法通过响应模型验证

代码定义

模型定义

class DeckBase(SQLModel):
    name: str = Field(sa_column=Column(TEXT))

    # Foreign keys
    owner_id: int = Field(foreign_key="player.id")

class Deck(DeckBase, table=True):
    id: int = Field(primary_key=True)

    # Relationships
    owner: Player = Relationship(back_populates="decks")
    cards: List["Card"] = Relationship(back_populates="decks", link_model=DeckCards)  # ManyToMany

响应模型

class DeckRead(DeckBase):
    id: int

异常接口实现

@router.get("/", response_model=List[DeckRead])
async def read_all(offset: int = 0,
                   limit: int = Query(default=100, le=100),
                   db: Session = Depends(DbContext().get_db)):
    decks = db.execute(select(Deck).offset(offset).limit(limit)).all()
    return decks

报错信息

fastapi.exceptions.ResponseValidationError: 3 validation errors:
  {'type': 'missing', 'loc': ('response', 0, 'name'), 'msg': 'Field required', 'input': (Deck(id=1, name='Fire deck', owner_id=1),)}
  {'type': 'missing', 'loc': ('response', 0, 'owner_id'), 'msg': 'Field required', 'input': (Deck(id=1, name='Fire deck', owner_id=1),)}
  {'type': 'missing', 'loc': ('response', 0, 'id'), 'msg': 'Field required', 'input': (Deck(id=1, name='Fire deck', owner_id=1),)}

正常运行的接口实现

@router.get("/", response_model=List[DeckRead])
async def read_all(offset: int = 0,
                   limit: int = Query(default=100, le=100),
                   db: Session = Depends(DbContext().get_db)):
    decks = db.get(Deck, 1)
    return [decks]

原因分析

db.execute(select(Deck)).all() 返回的是元组的列表,每个元素是包含单个Deck实例的元组(比如 (Deck(id=1, ...),)),而不是直接的Deck实例列表。Pydantic的响应模型List[DeckRead]期望接收Deck实例或可直接映射为DeckRead的对象,但元组无法被正确解析,因此抛出字段缺失的验证错误。

而db.get(Deck, 1)返回的是单个Deck实例,将其放入列表后,列表元素是符合要求的实例,因此能通过验证。

解决方案

有两种可行的修复方式:

  1. 使用scalars()提取实例:
decks = db.execute(select(Deck).offset(offset).limit(limit)).scalars().all()

scalars()会直接返回查询结果中的模型实例,.all()得到实例列表,可直接返回。

  1. 手动从元组中提取实例:
decks = db.execute(select(Deck).offset(offset).limit(limit)).all()
return [deck for deck, in decks]

通过列表推导式遍历元组列表,取出每个元组中的第一个元素(即Deck实例)。


内容的提问来源于stack exchange,提问作者Kamigaku

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 20:17:52