如何在SQLAlchemy声明式模型中获取关联关系的ID列表?
在SQLAlchemy中为关联关系添加ID列表字段的实现方式
当然可以实现这种声明式的ID列表映射,完全不用每次单独写查询!下面给你两种最简洁的实现方式,适配不同的SQLAlchemy版本:
1. 通用方案(适配所有SQLAlchemy版本):column_property + 子查询聚合
直接在Delivery类里定义order_ids为一个计算属性,通过子查询聚合关联的Order ID,这是最直接的声明式实现:
from sqlalchemy import func, select class Delivery(Base): __tablename__ = "delivery" # 保留原有字段... id = sa.Column(GUID, primary_key=True, default=GUID_DEFAULT_SQLITE) orders = sa.orm.relationship("Order", lazy="subquery") # 新增order_ids字段,自动映射关联的订单ID列表 order_ids = sa.orm.column_property( select(func.array_agg(Order.id)) .where(Order.delivery_id == id) .scalar_subquery() .label("order_ids") )
数据库适配说明
- 如果你用的是PostgreSQL,
array_agg可以直接返回数组类型,完美匹配列表需求。 - 如果是SQLite,需要换成SQLite支持的JSON聚合函数
json_group_array(返回JSON数组,读取时会自动转成Python列表):# SQLite适配版本 order_ids = sa.orm.column_property( select(func.json_group_array(Order.id)) .where(Order.delivery_id == id) .scalar_subquery() .label("order_ids") )
2. SQLAlchemy 2.0+ 专属:hybrid_property 灵活方案
如果你的项目用的是SQLAlchemy 2.0及以上版本,hybrid_property是更灵活的选择——它既支持从已加载的关联对象中直接提取ID(避免额外查询),也支持用这个字段做查询过滤:
from sqlalchemy.ext.hybrid import hybrid_property class Delivery(Base): __tablename__ = "delivery" # 保留原有字段... id = sa.Column(GUID, primary_key=True, default=GUID_DEFAULT_SQLITE) orders = sa.orm.relationship("Order", lazy="subquery") @hybrid_property def order_ids(self): # 当已加载orders关联时,直接从内存提取ID,无需额外查询 return [order.id for order in self.orders] @order_ids.inplace.expression def order_ids(cls): # 当用于查询条件时,自动生成聚合SQL return select(func.array_agg(Order.id))\ .where(Order.delivery_id == cls.id)\ .scalar_subquery()
比如你可以直接用Delivery.order_ids.contains(some_order_id)来过滤包含特定订单ID的配送记录,非常方便。
最优选择建议
- 如果你只需要读取ID列表,不需要用这个字段做查询过滤,第一种
column_property方案最简洁,代码量最少。 - 如果需要同时支持读取和查询过滤,第二种
hybrid_property方案更实用,适配场景更广。
内容的提问来源于stack exchange,提问作者Chobeat
相关产品推荐
相关产品推荐

