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

FastAPI中SQLAlchemy使用load_only未按需加载列的问题

问题

在FastAPI项目中,我有一个包含6列的PostSQL表模型,尝试仅查询其中2列数据时遇到问题:

  • 使用select(PostSQL.id, PostSQL.title)查询,得到元组列表:[(1, 'hello'), (2, 'hello')]
  • 使用select(PostSQL).options(load_only(PostSQL.id, PostSQL.title))查询时,返回的PostSQL对象看起来包含了所有列的数据。

附上调试代码及结果:

@router.get("/custom1", status_code=status.HTTP_200_OK)
async def get_custom_posts(db: AsyncSession = Depends(get_async_db), current_user=Depends(get_current_user)):
    query = select(PostSQL.id, PostSQL.title).order_by(PostSQL.id)
    query2 = select(PostSQL).options(load_only(PostSQL.id, PostSQL.title)).order_by(PostSQL.id)
    query3 = select(PostSQL)
    
    result = await db.execute(query)  # <sqlalchemy.engine.result.ChunkedIteratorResult object at 0x104c2b900>
    result2 = await db.execute(query2)  # <sqlalchemy.engine.result.ChunkedIteratorResult object at 0x104c3c580>
    result3 = await db.execute(query3)  # <sqlalchemy.engine.result.ChunkedIteratorResult object at 0x104c709c0>

    post = result.all() # [(1, 'helo'), (2, 'helo'), (3, 'helo')]
    post2 = result2.scalars().all() # [<app.models.PostSQL object at 0x104c33a90>, <app.models.PostSQL object at 0x104c33850>]
    post3 = result3.all() # [(<app.models.PostSQL object at 0x104c339a0>,), (<app.models.PostSQL object at 0x104c33910>,), (<app.models.PostSQL object at 0x104c33a90>,)]
    return post2

原因分析

load_only的作用是限制SQLAlchemy从数据库加载的列,但它不会修改模型类的结构——模型本身仍定义了全部6列。当你访问未加载的列时,SQLAlchemy会触发懒加载(额外查询数据库)获取对应值,这会让你误以为对象包含了所有列数据。

实际从query2返回的PostSQL对象中,只有id和title是初始查询加载到内存的,其他列并未被加载。你可以打印对象的__dict__属性验证:未加载的列不会出现在__dict__中,或带有_sa_instance_state相关标记。

另外,FastAPI自动序列化模型对象时,会尝试访问所有字段,这会触发懒加载,进一步造成“所有列都被加载”的错觉。

解决方法

方法1:转换为自定义结构(推荐)

继续使用select(PostSQL.id, PostSQL.title),将结果转换为字典或Pydantic模型返回,避免触发懒加载:

# 转换为字典
posts = result.all()
return [{"id": p[0], "title": p[1]} for p in posts]

# 或使用Pydantic模型
from pydantic import BaseModel
class PostShort(BaseModel):
    id: int
    title: str

return [PostShort(id=p[0], title=p[1]) for p in posts]

方法2:控制模型对象的序列化

如果要返回模型对象,需确保只序列化需要的字段:

  • 可以在Pydantic模型中只定义需要的字段,用它来序列化SQLAlchemy对象;
  • 或手动提取所需字段转换为字典后返回,避免访问未加载的列。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 01:57:08