On my Pyramid+SQLAlchemy website I want a customer to view all purchases he has placed. A Purchase has many PurchaseOrder and an PurchaseOrder has many PurchaseOrderDetail.
I want to get all the Purchase context (including orders and details) in an optimized way and therefore I'm looking at SQLAlchemy loading strategies.
My model declaration looks like this:
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)
And what I would like is something in this form:
    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()
However, the Purchase.orders.details part is not allowed and raises the following exception:
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'
So, my questions are:
Thanks in advance
The subqueryload_all function is deprecated since version 0.9. 
Use method chaining with subqueryload instead:
from sqlalchemy.orm import subqueryload
session.query(MyClass).options(
    subqueryload("someattribute").subqueryload("anotherattribute")
)
                        Changing the subqueryload_all(...) part of your query to one of the two following options will do the job:
# 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
    )
Documentation on sqlalchemy.orm.subqueryload_all is pretty clear on this in the examples listed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With