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
相关产品推荐
相关产品推荐

