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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 05:18:21