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

FastAPI+SQLAlchemy多对多查询返回元组引发验证错误求助

问题解决:多对多关系查询返回元组导致FastAPI验证失败

问题根源

你的查询结果返回的是单元素元组列表(如(<Buyer(...)>,)),而非Buyer对象列表。这是因为SQLAlchemy的Result.all()会返回完整的查询行,当仅查询单个实体时,每行是一个包含该实体的元组。Pydantic模型期望直接接收ORM对象,因此无法从元组中读取属性,导致验证错误。

修复步骤

1. 修正查询结果提取方式

将result.all()替换为result.scalars().all(),scalars()会提取每行的第一个元素(即Buyer对象),返回纯实体列表:

async def get_all_buyers(self, session: AsyncSession):
    statement = (
        select(Buyer)
        .options(selectinload(Buyer.hs_codes))
        .order_by(desc(Buyer.created_at))
    )

    result = await session.exec(statement)
    # 用scalars().all()替代all(),获取实体对象列表
    buyers = result.scalars().all()
    
    return buyers

2. 修正代码缩进

你的return buyers语句存在缩进错误(比上一行多了额外空格),需确保它与函数内其他代码处于同一缩进级别,避免因缩进导致逻辑错误。

额外优化建议

  • DateTime字段类型匹配:你的Pydantic模型中created_at和updated_at定义为str,但SQLAlchemy模型是DateTime类型。建议将Pydantic模型中的类型改为datetime,FastAPI会自动将其序列化为ISO格式字符串:

    from datetime import datetime
    
    class BuyerResponseModel(BaseModel):
        company_name: str
        region: str
        country: str
        city: str
        company_size: str
        hs_codes: List[HSCodeResponse]
        created_at: datetime
        updated_at: datetime
    
        class Config:
            from_attributes = True
    
  • 移除Mixin表名冲突:你的TimestampMixin中用@declared_attr定义了__tablename__,但Buyer类又显式指定了表名,建议移除Mixin中的表名定义,避免潜在冲突:

    class TimestampMixin(object):
        # 移除这部分表名定义
        # @declared_attr
        # def __tablename__(cls):
        #     return cls.__name__.lower()
    
        created_at = mapped_column(DateTime, nullable=False, server_default=func.now())
        updated_at = mapped_column(
            DateTime, nullable=False, server_default=func.now(), onupdate=func.now()
        )
    

验证修复

修改后重新测试接口,查询结果会返回Buyer对象列表,Pydantic可以正常解析其属性,生成符合要求的JSON响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:59:50