I've got the first half of a fix for this issue up in gerrit review but unfortunately there are additional issues entirely on top of the thing I just fixed specific to your example in that it involves correlated subqueries that have to be matched. Was hoping to report a fix today but again I have no ETA on your specific use case.
On Sun, Aug 20, 2017 at 11:08 PM, Mike Bayer <mike...@zzzcomputing.com> wrote: > On Sun, Aug 20, 2017 at 10:18 AM, Stephen Early > <s...@individualpubs.co.uk> wrote: >> I've cut my code down somewhat; I don't think it's minimal but it does >> demonstrate the problem. It's at >> https://gist.github.com/sde1000/89b6ed13205faf0f019431183d1511bf and also >> pasted below: > > thanks. undefer_group() is not working off of an eagerload right now > and > https://bitbucket.org/zzzeek/sqlalchemy/issues/4048/undefer_group-from-relationship-path-has > is added to address this (will work off of a lazyload() though). In > addition a regression was also found in the 1.2 beta series related to > this pattern as well. Unfortunately I don't have an ETA for the > initial issue so you'll have to forego the use of undefer_group() in > this situation. > > > >> >> from sqlalchemy import create_engine >> from sqlalchemy.ext.declarative import declarative_base >> from sqlalchemy import Column, Integer, ForeignKey, Numeric >> from sqlalchemy.schema import Sequence, MetaData >> from sqlalchemy.sql.expression import text >> from sqlalchemy.orm import sessionmaker >> from sqlalchemy.orm import relationship, backref, column_property >> from sqlalchemy.orm import defaultload, joinedload >> from sqlalchemy.sql import select, func >> >> metadata = MetaData() >> >> Base = declarative_base(metadata=metadata) >> >> deliveries_seq = Sequence('deliveries_seq') >> class Delivery(Base): >> __tablename__ = 'deliveries' >> id = Column('deliveryid', Integer, deliveries_seq, >> nullable=False, primary_key=True) >> >> stock_seq = Sequence('stock_seq') >> class StockItem(Base): >> __tablename__ = 'stock' >> id = Column('stockid', Integer, stock_seq, nullable=False, >> primary_key=True) >> deliveryid = Column(Integer, ForeignKey('deliveries.deliveryid'), >> nullable=False) >> delivery = relationship(Delivery, backref=backref('items', order_by=id)) >> size = Column(Numeric(8, 1), nullable=False) >> >> stockout_seq = Sequence('stockout_seq') >> class StockOut(Base): >> __tablename__ = 'stockout' >> id = Column('stockoutid', Integer, stockout_seq, >> nullable=False, primary_key=True) >> stockid = Column(Integer, ForeignKey('stock.stockid'), nullable=False) >> stockitem = relationship(StockItem, backref=backref('out', order_by=id)) >> qty = Column(Numeric(8, 1), nullable=False) >> >> StockItem.used = column_property( >> select([func.coalesce(func.sum(StockOut.qty), text("0.0"))]).\ >> correlate(StockItem.__table__).\ >> where(StockOut.stockid == StockItem.id).\ >> label('used'), >> deferred=True, >> group="qtys", >> doc="Amount of this item that has been used for any reason") >> StockItem.remaining = column_property( >> select([StockItem.size - >> func.coalesce(func.sum(StockOut.qty), text("0.0"))]).\ >> where(StockOut.stockid == StockItem.id).\ >> label('remaining'), >> deferred=True, >> group="qtys", >> doc="Amount of this item remaining") >> >> engine = create_engine('sqlite://', echo=True) >> metadata.bind = engine >> metadata.create_all() >> >> sm = sessionmaker(bind=engine) >> s = sm() >> >> # Add test data >> delivery = Delivery() >> item = StockItem(delivery=delivery, size=72) >> used = StockOut(stockitem=item, qty=12) >> >> s.add_all([item, used]) >> >> s.commit() >> >> d_id = delivery.id >> >> print("\n\n\n\nTrying with no undefer option...") >> # I expect this query to complete in two round-trips to the database, >> # and it does. >> s = sm() >> d = s.query(Delivery).\ >> filter_by(id=d_id).\ >> options(joinedload("items")).\ >> one() >> print("used: {}; remaining: {}".format(d.items[0].used, >> d.items[0].remaining)) >> >> print("\n\n\n\nTrying with undefer_group()...") >> # I expect this query to complete in one round-trip to the database, >> # but it takes two. >> s = sm() >> d = s.query(Delivery).\ >> filter_by(id=d_id).\ >> options(joinedload("items")).\ >> options(defaultload("items").undefer_group('qtys')).\ >> one() >> print("used: {}; remaining: {}".format(d.items[0].used, >> d.items[0].remaining)) >> >> print("\n\n\n\nTrying with separate undefer() calls...") >> # I expect this query to complete in one round-trip to the database, >> # and it does. >> s = sm() >> d = s.query(Delivery).\ >> filter_by(id=d_id).\ >> options(joinedload("items")).\ >> options(defaultload("items").undefer('used').undefer('remaining')).\ >> one() >> print("used: {}; remaining: {}".format(d.items[0].used, >> d.items[0].remaining)) >> >> >> Stephen Early >> >> On Sunday, 20 August 2017 14:34:16 UTC+1, Mike Bayer wrote: >>> >>> I would need mappings / MCVE to work with this problem. >>> >>> On Aug 20, 2017 9:01 AM, "Stephen Early" <s...@individualpubs.co.uk> >>> wrote: >>>> >>>> I'm having trouble with undefer_group(), which I'm sure used to work for >>>> me but now doesn't! >>>> >>>> I've read the documentation regarding the changes to undefer_group() in >>>> 0.9; I'm now using 1.0.14 >>>> >>>> I have a model, StockItem, with three column properties ('used', 'sold', >>>> 'remaining') that are all deferred and in group 'qtys'. Let's say I do a >>>> query like this (Delivery.items is a backref to StockItem): >>>> >>>> d = session.query(Delivery).\ >>>> filter_by(id=int(deliveryid)).\ >>>> options(joinedload_all('items.stocktype.unit'), >>>> joinedload_all('items.stockline'), >>>> defaultload("items").undefer_group('qtys')).\ >>>> one() >>>> >>>> I would expect StockItem.used, StockItem.sold and StockItem.remaining to >>>> be undeferred, but they are not. If I do this: >>>> >>>> d = session.query(Delivery).\ >>>> filter_by(id=int(deliveryid)).\ >>>> options(joinedload_all('items.stocktype.unit'), >>>> joinedload_all('items.stockline'), >>>> defaultload("items")\ >>>> .undefer('used')\ >>>> .undefer('sold')\ >>>> .undefer('remaining')).\ >>>> one() >>>> >>>> ...then it works as expected. >>>> >>>> The 'used', 'sold' and 'remaining' columns are added to the StockItem >>>> class after it's defined, as follows: >>>> >>>> StockItem.used = column_property( >>>> select([func.coalesce(func.sum(StockOut.qty), text("0.0"))]).\ >>>> correlate(StockItem.__table__).\ >>>> where(StockOut.stockid == StockItem.id).\ >>>> label('used'), >>>> deferred=True, >>>> group="qtys", >>>> doc="Amount of this item that has been used for any reason") >>>> >>>> Any ideas? >>>> >>>> Stephen Early >>>> >>>> -- >>>> SQLAlchemy - >>>> The Python SQL Toolkit and Object Relational Mapper >>>> >>>> http://www.sqlalchemy.org/ >>>> >>>> To post example code, please provide an MCVE: Minimal, Complete, and >>>> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >>>> description. >>>> --- >>>> You received this message because you are subscribed to the Google Groups >>>> "sqlalchemy" group. >>>> To unsubscribe from this group and stop receiving emails from it, send an >>>> email to sqlalchemy+...@googlegroups.com. >>>> To post to this group, send email to sqlal...@googlegroups.com. >>>> Visit this group at https://groups.google.com/group/sqlalchemy. >>>> For more options, visit https://groups.google.com/d/optout. >> >> -- >> SQLAlchemy - >> The Python SQL Toolkit and Object Relational Mapper >> >> http://www.sqlalchemy.org/ >> >> To post example code, please provide an MCVE: Minimal, Complete, and >> Verifiable Example. See http://stackoverflow.com/help/mcve for a full >> description. >> --- >> You received this message because you are subscribed to the Google Groups >> "sqlalchemy" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to sqlalchemy+unsubscr...@googlegroups.com. >> To post to this group, send email to sqlalchemy@googlegroups.com. >> Visit this group at https://groups.google.com/group/sqlalchemy. >> For more options, visit https://groups.google.com/d/optout. -- SQLAlchemy - The Python SQL Toolkit and Object Relational Mapper http://www.sqlalchemy.org/ To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description. --- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+unsubscr...@googlegroups.com. To post to this group, send email to sqlalchemy@googlegroups.com. Visit this group at https://groups.google.com/group/sqlalchemy. For more options, visit https://groups.google.com/d/optout.