SQLAlchemy查询关联数据时如何展开关联字段而非返回嵌套对象
SQLAlchemy 获取非嵌套关联数据的实现方案
现有手动遍历setattr的方案冗余度高,以下三种方案可以实现关联字段自动展平,按需选择即可:
方案1:查询阶段直接联表返回扁平结构
性能最优,不需要额外加载完整的关联User对象,直接在查询时指定需要的字段,将关联表字段别名映射为外层属性,查询结果直接就是目标结构:
# 单条查询示例 comment = db.query( KanbanComment.id, KanbanComment.message, User.name.label("name"), User.avatar.label("avatar") ).join(KanbanComment.user) .filter(KanbanComment.id == target_id) .first() # 列表查询示例 comment_list = db.query( KanbanComment.id, KanbanComment.message, User.name.label("name"), User.avatar.label("avatar") ).join(KanbanComment.user) .filter(KanbanComment.card_id == target_card_id) .all()
该方案查询结果不会返回嵌套的user对象,返回值直接匹配需要的响应结构,适合字段固定的高性能接口场景。
方案2:Pydantic响应模型自动展平(FastAPI生态首选)
如果项目用FastAPI的response_model做响应序列化,完全不需要修改ORM查询逻辑,也不需要手动修改实例属性,只要在响应Schema里配置字段的取值路径,序列化时会自动从嵌套关系中提取字段展平到外层:
from pydantic import BaseModel, Field class CommentResponse(BaseModel): id: int message: str # 配置从嵌套的user对象中取对应字段 name: str = Field(validation_alias="user.name") avatar: str | None = Field(validation_alias="user.avatar") class Config: # Pydantic V2用该配置,V1版本替换为 orm_mode = True from_attributes = True
配置完成后,哪怕查询结果是带嵌套user结构的ORM对象,序列化输出时也会自动生成扁平结构,不需要额外的遍历赋值操作,维护成本最低。
方案3:ORM模型层配置关联属性代理
如果多个业务场景都需要访问展平后的用户字段,可以直接在模型层用column_property把关联表的字段代理为当前模型的原生属性,所有查询返回的评论实例都可以直接访问name、avatar属性,和访问自身字段没有区别:
from sqlalchemy.orm import column_property from sqlalchemy import select class KanbanComment(Base): __tablename__ = "kanban_comment" id = Column(Integer, primary_key=True, index=True) message = Column(String, nullable=False) user_id = Column(Integer, ForeignKey("user.id")) user = relationship("User") # 代理User表的字段为评论模型自身属性 name = column_property( select(User.name) .where(User.id == user_id) .correlate_except(User) .scalar_subquery() ) avatar = column_property( select(User.avatar) .where(User.id == user_id) .correlate_except(User) .scalar_subquery() )
该方案属于一劳永逸的配置,配置后原有查询逻辑不需要任何修改,只要在序列化时排除嵌套的user字段即可得到扁平结构。
选型参考:
- 追求查询性能、接口字段固定选方案1
- 基于FastAPI+Pydantic开发接口选方案2,无侵入易维护
- 多场景复用展平字段选方案3,模型层统一配置
内容的提问来源于stack exchange,提问作者Marvin Ludwig
相关产品推荐
相关产品推荐

