如何在 SQLAlchemy 中加载嵌套关系?

Posted

技术标签:

【中文标题】如何在 SQLAlchemy 中加载嵌套关系?【英文标题】:How to load nested relationships in SQLAlchemy? 【发布时间】:2012-10-02 21:39:37 【问题描述】:

在我的 Pyramid+SQLAlchemy 网站上,我希望客户查看他下的所有购买。一个 Purchase 有多个 PurchaseOrder,一个 PurchaseOrder 有多个 PurchaseOrderDetail。

我想以优化的方式获取所有购买上下文(包括订单和详细信息),因此我正在研究 SQLAlchemy 加载策略。

我的模型声明如下所示:

class Purchase(Base):
    __tablename__ = 'purchase'
    __table_args__ = 'schema':'db','autoload':True

    customer = relationship(Customer)
    billing_address = relationship(Address,primaryjoin="Address.AddressId==Purchase.BillingAddressId")
    shipping_address = relationship(Address,primaryjoin="Address.AddressId==Purchase.ShippingAddressId")
    orders = relationship(PurchaseOrder)

class PurchaseOrder(Base):
    __tablename__ = 'purchase_order'
    __table_args__ = 'schema':'db','autoload':True

    company = relationship(Company)
    delivery_service = relationship(DeliveryService)
    details = relationship(PurchaseOrderDetail)

class PurchaseOrderDetail(Base):
    __tablename__ = 'purchase_order_detail'
    __table_args__ = 'schema':'db','autoload':True

    product_variant = relationship(ProductVariant)

我想要的是这种形式的东西:

    db_session = DBSession()
    p = db_session.query(Purchase).\
        options(joinedload_all(Purchase.customer,
                                Purchase.billing_address,
                                Purchase.shipping_address)
                ,subqueryload_all(Purchase.orders,
                                Purchase.orders.details)).all()

但是,Purchase.orders.details 部分是不允许的,并引发以下异常:

Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "C:\apps\pyramid\lib\site-packages\sqlalchemy\orm\attributes.py", line 139, in __getattr__
    key)
AttributeError: Neither 'InstrumentedAttribute' object nor 'Comparator' object has an attribute 'details'

所以,我的问题是:

    查询采购时如何加载 PurchaseOrderDetails 模型? 这是获得所有购买信息的最佳方式吗?

提前致谢

【问题讨论】:

【参考方案1】:

subqueryload_all 函数自 0.9 版起已弃用。

改用subqueryload 的方法链接:

from sqlalchemy.orm import subqueryload

session.query(MyClass).options(
    subqueryload("someattribute").subqueryload("anotherattribute")
)

【讨论】:

【参考方案2】:

将查询的 subqueryload_all(...) 部分更改为以下两个选项之一即可:

# option-1:
subqueryload_all(
    'orders.details', # @note: this will load both *orders* and their *details*
    )

# option-2:
subqueryload_all(
    Purchase.orders,       # @note: this will load orders
    PurchaseOrder.details, # @note: this will load orders' details
    )

sqlalchemy.orm.subqueryload_all 上的文档在列出的示例中对此非常清楚。

【讨论】:

这比我预期的要容易:) 谢谢!我会选择第二个选项 对于那些将来阅读本文的人,请知道 subqueryload_all 和joinedload_all 在 sqlalchemy 0.9.0 docs.sqlalchemy.org/en/latest/orm/… 中已弃用

以上是关于如何在 SQLAlchemy 中加载嵌套关系?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Laravel中加载嵌套关系

Logstash 2.3.4如何使用logstash-jdbc插件在Elasticsearch中加载嵌套文档

在 ExtJS4 TreeGrid 中加载嵌套的 JSON 数据

如何从不带引号的文件中加载嵌套列表?

嵌套的一对多关系 sqlalchemy 过滤

如何在 Data Mapper 中加载一对多关系?