FastAPI中用SQLModel实现关联查询返回嵌套结构报错求助
问题解决:FastAPI + SQLModel 实现关联查询并返回嵌套响应结构
你当前的核心问题是:查询返回的是Attack和Option的元组列表,但接口声明要返回list[AttackOption],结构完全不匹配,导致验证失败;同时模型未建立关联关系,无法直接获取嵌套的options数据。以下是分步解决方案:
1. 给表模型添加关联关系
修改Attack和Option模型,用Relationship建立一对多关联,让SQLModel可以直接加载关联数据:
from sqlmodel import Relationship # 新增导入 class Attack(SQLModel, table=True): __tablename__ = "attacks_attack" attack_id: int | None = Field(default=None, primary_key=True) name: str module: str # 新增:关联对应的Option列表,反向关联字段为Option.attack options: list["Option"] = Relationship(back_populates="attack") class Option(SQLModel, table=True): __tablename__ = "attacks_option" option_id: int | None = Field(default=None, primary_key=True) name: str attack_id : int = Field(default=None, foreign_key='attacks_attack.attack_id') # 新增:反向关联Attack实例 attack: Attack = Relationship(back_populates="options")
2. 调整响应模型匹配期望输出
响应模型不需要table=True,且字段名要和你期望的嵌套结构对齐:
# 顶层响应模型 class AttackOption(SQLModel): attack_id: int attack_name: str # 对应Attack表的name字段 module: str options: list["OptionResponse"] # 嵌套子响应模型 # 嵌套的Option响应模型 class OptionResponse(SQLModel): option_id: int option_name: str # 对应Option表的name字段
3. 修改查询与数据转换逻辑
直接查询Attack并预加载关联的options,再将数据库模型转换为响应模型结构:
from sqlmodel import selectinload # 新增导入 @app.get("/attacks/") def read_attacks( session: SessionDep, offset: int = 0, limit: Annotated[int, Query(le=100)] = 1, ) -> list[AttackOption]: # 用selectinload预加载关联的options,避免N+1查询问题 attacks = session.exec( select(Attack).options(selectinload(Attack.options)).offset(offset).limit(limit) ).all() # 转换为期望的嵌套响应结构 result = [] for attack in attacks: # 转换每个Option为OptionResponse option_list = [ OptionResponse(option_id=opt.option_id, option_name=opt.name) for opt in attack.options ] # 组装顶层AttackOption result.append( AttackOption( attack_id=attack.attack_id, attack_name=attack.name, module=attack.module, options=option_list ) ) return result
错误原因说明
你之前使用select(Attack, Option).join(Option)查询,返回的是(Attack实例, Option实例)的元组列表,但接口声明要返回AttackOption类型。元组本身没有attack_name、options等响应模型要求的字段,因此触发了Field required的验证错误。
内容的提问来源于stack exchange,提问作者soylentkim
相关产品推荐
相关产品推荐

