On 3/23/07, Michael Bayer <[EMAIL PROTECTED]> wrote:

> OK, this is actually something people have asked for a lot.  in the
> beginning, recently, etc.  also for different reasons...i.e.
> convenience, or performance, etc.   So, first off let me start by
> illustrating how this use case is done right now.   Assuming your
> Address mapper has a backref "user" to the User mapper, its  just:
>
>         for address in session.query(Address).filter_by(user=someuser).filter
> (address_table.c.postcode == 5000):
>                 print address.street

Once again, I discover a "better way" to do something I did the hard way.

> But,  the join conditions and bind params which
> have been calculated by "LazyLoader" are just sitting there, they can
> be currently pulled out with a little non-API attribute access but
> Ive no problem with adding some API-level accessors to get at the
> Query object calculated for a particular property (i.e. what you are
> using in your patch internally).

Yes, please do, that'd probably solve the problem nicely (see below
how I see things).


> now lets look at the way your patch does it.
>
>         addresses = user.addresses.filter(address_table.c.postcode == 5000)

> seems easy.  right ?  remember that "user" is now in the session.
> anyone else that queries for "user" will get that same User
> instance.  but the rest of the app is going to assume normal
> relationship semantics on that collection....which means:

How I envisioned things, this wouldn't be a problem, because
user.addresses.filter(xxx) would return a new, independant list, which
doesn't affect user.addresses, and is not affected if user.addresses
has already been accessed or not. This is not what my patch does, I
know. Sorry for not explaining this in my first mail.

>         print someaddress in user.addresses # <-- FAIL - the address is not
> present
>         user.addresses.remove(someaddress) # <-- ERROR - the address is not
> present
>
>         user.addresses.insert(5, someotheraddress) # <-- FAIL - the list is
> incomplete, ordering will be incorrect

This is only a matter of getattr and __contains__ triggering init,
right? (At least if we exclude the other problems pointed above).

>         session.flush()  # <-- FAIL - we have to figure out what items were
> added/removed/unchanged from the collection...but the data's
> incomplete !

I don't master SQLAlchemy internals but I don't see how that is
different from when the collection is complete?

> so as long as we can agree on the "its a read-only thing" aspect of
> this, we're good to go.  otherwise you have to define for me how all
> those mutating operations are going to work (and even then, its
> additional core complexity im not sure if i can add to my support-load).

I'm fine with the readonly aspect of it. What I don't like is the fact
you have to create a readonly relation (lazyloader/whatever/...) in
advance (ie in your mapper), which is IMHO just a dupe of the normal
relation and pollutes the mapper. You'd end up with mappers like this:

         mapper(SomeClass, table, properties={
                 'addresses':relation(Address)
                 'addresses2':lazyloader(Address)
         })

which is pretty much as ugly as you can get.

On the other hand, I think that combined with a quick way to have
predefined filters it might be a nice addition anyway:

         mapper(SomeClass, table, properties={
                 'addresses': relation(Address)
                 'local_addresses': lazyloader(Address,
filter=address.c.postcode==5000)
         })

But it does in no case replace the "dynamic" "non-polluting" use-case
I'd like to have. What I had in mind is to reuse normal relations to
get a query. It feels much more natural and cleaner to me. And I think
the best compromise would be something along the lines of:

user.addresses: # use standard relation => read/write
user.addresses.filter(XXX): # returns a query => read only

the code would probably be cleaner if we did something more explicit like:

user.addresses.query # returns the query object that you can filter, etc...

though, as a user, I'd prefer the first solution.

Wouldn't that be possible? I think it should be. You only need to keep
the deferred approach of the InstrumentedList that I demonstrated in
my patch, so that the whole list is not fetched before we get the
query object, which would ruin the whole idea. Of course it was only a
proof-of-concept patch, but I think it should be fixable.

-- 
Gaƫtan de Menten
http://openhex.org

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

Reply via email to