[sqlalchemy] How to order_by relation by another join?

2010-02-10 Thread Andrija Zarić
Let's say I've got simple structure Order--Item--Detail.

class Detail(Base):
   ...

class Order(Base):
  ...

class Item(Base):
  ...
  detail = relation(Detail, uselist=False, lazy=False)
  order = relation(Order, uselist=False, backref='items')

Of course I can specify order_by for Order.items by any columns from
Item, but is there a way I can order_by a column defined in Detail?

I've naively tried something as backref('items', order_by=Detail.id),
but because Detail is anonymously joined to Item as e.g. 'details_1',
I've received ProgrammingError:  invalid reference to FROM-clause
entry for table details.

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] How to order_by relation by another join?

2010-02-10 Thread Michael Bayer

On Feb 10, 2010, at 10:17 AM, Andrija Zarić wrote:

 Let's say I've got simple structure Order--Item--Detail.
 
 class Detail(Base):
   ...
 
 class Order(Base):
  ...
 
 class Item(Base):
  ...
  detail = relation(Detail, uselist=False, lazy=False)
  order = relation(Order, uselist=False, backref='items')
 
 Of course I can specify order_by for Order.items by any columns from
 Item, but is there a way I can order_by a column defined in Detail?
 
 I've naively tried something as backref('items', order_by=Detail.id),
 but because Detail is anonymously joined to Item as e.g. 'details_1',
 I've received ProgrammingError:  invalid reference to FROM-clause
 entry for table details.

The Order.items collection doesn't have the ability to order by a remote column 
in the collection, unless you set the order_by to a subquery that joined out to 
the ultimate target you care about.   

Maybe, I haven't tried this, you could make an alternate (non primary) mapping 
to Item that was a join of Item and Detail, i.e. like:

itemdetail = mapper(Item.__table__.join(Detail.__table__), non_primary=True)

Order.items = relation(itemdetail, order_by=itemdetail.c.detail_id)

I'm not 100% sure the non-primary mapper allowing additional attributes, and it 
might need to be a mapping of a select().select_from(join) and not the join 
directly, but if you have some time to experiment you might get something out 
of that.








 
 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To post to this group, send email to sqlalch...@googlegroups.com.
 To unsubscribe from this group, send email to 
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at 
 http://groups.google.com/group/sqlalchemy?hl=en.
 

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] How to order_by relation by another join?

2010-02-10 Thread Michael Bayer

On Feb 10, 2010, at 10:34 AM, Michael Bayer wrote:

 Maybe, I haven't tried this, you could make an alternate (non primary) 
 mapping to Item that was a join of Item and Detail, i.e. like:
 
 itemdetail = mapper(Item.__table__.join(Detail.__table__), non_primary=True)
 
 Order.items = relation(itemdetail, order_by=itemdetail.c.detail_id)
 
 I'm not 100% sure the non-primary mapper allowing additional attributes, and 
 it might need to be a mapping of a select().select_from(join) and not the 
 join directly, but if you have some time to experiment you might get 
 something out of that.

Here, I think it works:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite://', echo=True)
Base = declarative_base()

class Detail(Base):
__tablename__ = 'detail'

id = Column(Integer, primary_key=True)
item_id = Column(Integer, ForeignKey('item.id'))

class Order(Base):
__tablename__ = 'order'
id = Column(Integer, primary_key=True)

class Item(Base):
__tablename__ = 'item'
id = Column(Integer, primary_key=True)
order_id = Column(Integer, ForeignKey('order.id'))

detail = relation(Detail, uselist=False, lazy=False)
order = relation(Order, uselist=False)
 
j = Item.__table__.join(Detail.__table__)
itemdetail = mapper(Item, j, non_primary=True)
Order.items = relation(itemdetail, order_by=j.c.detail_id, viewonly=True)
 
metadata = Base.metadata
metadata.create_all(engine)
Session = scoped_session(sessionmaker(bind=engine))
Session.query(Order).options(eagerload(Order.items)).all()

the query is:

 SELECT order.id AS order_id, anon_1.item_id AS anon_1_item_id, 
anon_1.detail_id AS anon_1_detail_id, anon_1.item_order_id AS 
anon_1_item_order_id, anon_1.detail_item_id AS anon_1_detail_item_id 
FROM order LEFT OUTER JOIN (SELECT item.id AS item_id, item.order_id AS 
item_order_id, detail.id AS detail_id, detail.item_id AS detail_item_id 
FROM item JOIN detail ON item.id = detail.item_id) AS anon_1 ON order.id = 
anon_1.item_order_id ORDER BY anon_1.detail_id

However I can't currently get back_populates or backref to relate the two 
sides together.   which isn't necessary if you dont need it.


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.