SQLAlchemy - 过滤子查询负载

Posted

技术标签:

【中文标题】SQLAlchemy - 过滤子查询负载【英文标题】:SQLAlchemy - Filter on Subqueryload 【发布时间】:2015-03-11 18:24:13 【问题描述】:

假设以下型号,如何通过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 因此,我只对在遍历所有订单时引用“活跃”的货件感兴趣。 subqueryload 返回的标准结果加载并返回所有货件 我正在使用最新的稳定版本的 SQLAlchemy。

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

提前致谢。

【问题讨论】:

【参考方案1】:

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

但是,目前,通过 relationship() 设置的属性契约是它们仅使用直接在 relationship() 中设置的标准。没有简单的方法可以在使用提供的加载器服务的同时即时更改标准。

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

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

【讨论】:

非常感谢!我希望这可能会在不久的将来添加到 SQA 核心中,但现在,手动设置它在关系上工作(尽管以有限的方式)就好了。 DisjointEagerLoading 似乎也适用于更强大的用例。 @Brownbay 建议的有趣 API。你认为实现像@zzzeek 这样的东西是可行的吗?我喜欢使用 contains_eager 的便利性,但有时在处理多层次关系时使用它太贵了。 这是可以做到的,但这将是一项巨大的努力,相比之下对它的需求并不多。 SQLA 现在的发展与 Postgresql 不断的新功能几乎没有同步。

以上是关于SQLAlchemy - 过滤子查询负载的主要内容,如果未能解决你的问题,请参考以下文章

在 Flask-SQLAlchemy 模型上使用函数查询会给出 BaseQuery object is not callable 错误

在 graphene-sqlalchemy 查询中按 id 过滤

SQLAlchemy:如何在连接查询中的过滤器之前应用 distinct

如何在 sqlalchemy 查询过滤器中使用用户定义的 python 函数?

需要帮助构建 SQLAlchemy 查询 + 子查询

Sqlalchemy 子查询