Thank you for the help! Additionally, I was wondering if it would be
able to make "newest_address" an attribute on the user class, which can
then be used in a query with ".options(joinedload('newest_address'))".
My goal would be that I get an attribute that returns the newest'
address date time on normal access and is also able to be eagerly
loaded/joined in a query object.  I read up in the docs and either
column_property or Correlated Subquery Relatonship Hybrid seems to be
made for this. Which one should I use?



ButAm 20.10.2013 04:41, schrieb Michael Bayer:
> On Oct 19, 2013, at 4:24 PM, Sebastian Elsner <sebast...@risefx.com> wrote:
>
>> Hello,
>>
>> using the Address and User example, where the Address is connected to
>> the User via a many-to-many relationship, I want to get all users with
>> the date of their newest address. This is what I have now:
>>
>> s.query(User, s.query(func.max(Address.created)).\
>> filter(Address.users.any()).correlate(User).as_scalar()).\
>>                    outerjoin(User.addresses).all()
>>
>> But this is giving me all users with the newest address in the whole
>> address table. I think the error is in the subquery's filter, but I fail
>> to see how I can fix it. I am also not tied to this query, so if you
>> know a better way to get a list of all Users and their newest address
>> date, shoot!
> the format for this is the "select user rows + an aggregate of a related 
> table", this format is illustrated here: 
> http://docs.sqlalchemy.org/en/rel_0_8/orm/tutorial.html#using-subqueries  
> where we illustrate the count of address rows per user. 
>
> I see here though you have an association table in between them so that just 
> has to be added to the subquery to create a row that goes across Address and 
> UserAddresses, same idea though, use subquery with aggregate + group_by, 
> (outer) join to that:
>
> subq = session.query(
>                 func.max(Address.created).label("created"),
>                 UserAddresses.user_id).join(UserAddresses).\
>                 group_by(UserAddresses.user_id).subquery()
>
> q = session.query(User, subq.c.created).outerjoin(subq)
> print q.all()
>
>
>
>
>> Here is a working example. As you can see if you run it, even Users with
>> no Addresses assigned will get the newest address date in the query.
>>
>> import datetime
>> from sqlalchemy.ext.declarative import declarative_base
>> from sqlalchemy.engine import create_engine
>> from sqlalchemy.orm.session import sessionmaker
>> from sqlalchemy.schema import Column, ForeignKey
>> from sqlalchemy.types import Integer, DateTime, String
>> from sqlalchemy.orm import relationship
>> from sqlalchemy.sql.expression import func
>>
>> Base = declarative_base()
>>
>>
>> class Address(Base):
>>    __tablename__ = 'address'
>>    id = Column(Integer, primary_key=True)
>>    created = Column(DateTime)
>>    users = relationship('User', back_populates='addresses',
>> secondary='useraddress')
>>
>>    def __repr__(self):
>>        return "Address: %s, %s" % (self.id, self.created)
>>
>>
>> class User(Base):
>>    __tablename__ = 'user'
>>    id = Column(Integer, primary_key=True)
>>    name = Column(String)
>>    addresses = relationship('Address', back_populates='users',
>> secondary='useraddress')
>>
>>    def __repr__(self):
>>        return "User: " + self.name
>>
>>
>> class UserAddresses(Base):
>>    __tablename__ = 'useraddress'
>>    user_id = Column(Integer, ForeignKey('user.id'), primary_key=True)
>>    address_id = Column(Integer, ForeignKey('address.id'), primary_key=True)
>>
>> engine = create_engine('sqlite://')
>> Base.metadata.create_all(engine)
>> session = sessionmaker(engine)()
>>
>> u1 = User(name="Foo")
>> u2 = User(name="Bar")
>> u1.addresses.append(Address(created=datetime.datetime.now()))
>> u1.addresses.append(Address(created=datetime.datetime.now() -
>> datetime.timedelta(days=1)))
>> session.add(u1)
>> session.add(u2)
>> session.commit()
>> print u1, u1.addresses
>> print u2, u2.addresses
>> print session.query(User, print session.query(User,
>> session.query(func.max(Address.created)).filter(Address.users.any()).correlate(User).as_scalar()).outerjoin(User.addresses).all()
>>
>> Cheers
>>
>> Sebastian
>>
>> -- 
>> 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 http://groups.google.com/group/sqlalchemy.
>> For more options, visit https://groups.google.com/groups/opt_out.

-- 
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 http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to