SQLAlchemy - 对子查询负载进行过滤

问题描述 投票:0回答:2

假设以下模型,究竟如何通过

subqueryload
加载与订单相关的发货,并按
is_refunded
的状态进行过滤?

class Order(db.Model):
    id = db.Column(db.Integer, primary_key=True)

class Shipment(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    shipment = db.Column(MutableDict.as_mutable(JSONB))
    is_refunded = db.Column(db.Boolean, server_default="false")
    order_id = db.Column(db.Integer, db.ForeignKey('order.id'))
    order = db.relationship('Order', backref='shipments')

我希望得到以下内容,但这不是有效的语法:

orders = db.session.query(Order).options(
    db.subqueryload(Order.shipments).filter(Shipment.is_refunded==False))

一些背景:

  • 订单到发货是一对多的关系。
  • 根据业务规则,虽然一个订单可能有多个发货,但只能有一个“活跃”发货。 IE。所有其他货件的
    is_refunded
    状态将设置为
    True
  • 因此,我只对在迭代所有订单时引用“活动”的发货感兴趣。
  • 子查询load返回的标准结果加载并返回所有发货
  • 我正在使用最新稳定版本的 SQLAlchemy。

如果需要任何说明,请告诉我。

提前致谢。

python python-3.x sqlalchemy
2个回答
7
投票

有趣的是,我一直想知道一种简单的“选项”方法来完成这种事情,所以上面的语法很有趣。

然而,目前,通过relationship()设置的属性的契约是它们仅使用直接在relationship()中设置的条件。 没有简单的方法可以在仍然使用所提供的加载程序服务的情况下动态更改标准。

直接使用具有自定义条件的加载器服务的两个选项是使用连接写出查询,然后与 contains_eager 组合(适用于 joinload,而不是真正的 subqueryload),或者使用新的关系()满足您正在寻找的标准(您通过primaryjoin建立)。

subqueryload 还存在另一个选项,即自己发出相同的查询,但实际上并不使用 subqueryload 选项。 这里的特殊技术是能够使用查询结果填充集合,这样它们就不会被记录为更改事件。 set_commissed_value 函数用于此目的,并且在 DisjointEagerLoading 处有一个说明 subqueryload 的“原始”形式(在内置之前)的示例来说明这一点。 对于绝大多数简单情况来说,针对固定实体滚动您自己的“子查询负载”并不是很难,该示例中说明了该技术。


0
投票

使用 SQLAlchemy 2 异步会话,您可以这样做:

from sqlalchemy import select
from sqlalchemy.orm import selectinload


statement = select(Order).options(selectinload(Order.shipments.and_(Shipment.is_refunded.is_(False))))

result = await db.session.execute(statement)
orders = result.scalars().all()
© www.soinside.com 2019 - 2024. All rights reserved.