That is for comparing *Clauses* and handles:
locations.siteid = :param_1
and
:param_1 = locations.siteid
However,
"locations.siteid = :param_1 AND locations.locationid = :param_2"
and
"locations.locationid = :param_1 AND locations.siteid = :param_2"
are ClauseLists, which compares their individual Clauses *in order*:
def compare(self, other, **kw):
"""Compare this :class:`ClauseList` to the given
:class:`ClauseList`,
including a comparison of all the clause items.
"""
if not isinstance(other, ClauseList) and len(self.clauses) == 1:
return self.clauses[0].compare(other, **kw)
elif isinstance(other, ClauseList) and \
len(self.clauses) == len(other.clauses):
for i in range(0, len(self.clauses)):
if not self.clauses[i].compare(other.clauses[i], **kw):
return False
else:
return self.operator == other.operator
else:
return False
(I know because if I flip the order of the composite
ForeignKeyConstraint it no longer calls .get() for the lazyload... it
always queries the database, so I checked out why in the debugger)
On 9/8/2010 1:27 PM, Michael Bayer wrote:
On Sep 8, 2010, at 1:15 PM, Kent Bower wrote:
I imagine you are already aware of this...
Unfortunately, the clause comparison says these two clauses are
different:
(Pdb) print self
locations.siteid = :param_1 AND locations.locationid = :param_2
(Pdb) print other
locations.locationid = :param_1 AND locations.siteid = :param_2
when they are really the equivalent. So composite foreign keys need
to be listed in the correct order for LazyLoader.use_get to optimize
the load with get().
use clause.compare(). Here's the source for _BinaryExpression:
def compare(self, other, **kw):
"""Compare this :class:`_BinaryExpression` against the
given :class:`_BinaryExpression`."""
return (
isinstance(other, _BinaryExpression) and
self.operator == other.operator and
(
self.left.compare(other.left, **kw) and
self.right.compare(other.right, **kw) or
(
operators.is_commutative(self.operator) and
self.left.compare(other.right, **kw) and
self.right.compare(other.left, **kw)
)
)
)
see the "commutative" in there ? its handled.
I already saw it would be somewhat of an effort to refactor the
clause comparison to work that out... bummer.
On 9/7/2010 7:28 PM, Michael Bayer wrote:
On Sep 7, 2010, at 6:41 PM, Kent Bower wrote:
Two items:
* How does the orm currently determine whether it is safe to try
get() (e.i. there are no "funny join conditions")? If you point me
to the function where decision takes place, I can probably answer
this myself....
it compares the join condition of the relationship() to that of the
clause which the Mapper uses when it issues get(), then stores that
away as a flag for future consultation. It's very unusual for a
many-to-one relationship to be based on something other than a
simple foreign-key->primary key relationship, though.
* When I build up the primary key from the foreign key, is there
an efficient way to build a composite key in the correct order to
pass to get()? (I thought maybe "synchronize_pairs", but that
maybe has to do with getting the direction consistent instead?)
Well if you aren't using any composite primary keys in many-to-ones,
you wouldn't even have to worry about this. Otherwise, the two
collections to correlate would be property.local_remote_pairs and
property.mapper.primary_key. Perhaps make a dictionary out of
dict([(r, l) for l, r in prop.local_remote_pairs]) and your PK value
would be [getattr(instance,
prop.parent.get_property_by_column(mydict[p]).key) for p in
property.mapper.primary_key].
Or if you want to get ambitious you can just copy roughly whats in
strategies.py on line 605 but then you're digging into
internals....and looking at that now I'm wondering if
strategy._equated_columns is really different than
local_remote_pairs at all...
Thanks again, you've been much help!
On 9/7/2010 5:03 PM, Michael Bayer wrote:
On Sep 7, 2010, at 4:38 PM, Kent Bower wrote:
Don't want to strangle me, but when the orm (lazy)loads a
MANYTONE object, it doesn't go to the database if the object is
in the session. Can I get "with_parent()" to behave this way, or
would I need to specifically build up the primary key of the
related object and call query.get()?
the latter. You can use get() for all many to ones if you aren't
using any funny join conditions.
On 9/7/2010 10:25 AM, Michael Bayer wrote:
On Sep 7, 2010, at 10:12 AM, Kent Bower wrote:
Mike, in your proof of concept, when __getstate__ detected
transient, why did you need to make a copy of self.__dict__?
"self.__dict__.copy()"
i was modifying the __dict__ from what would be expected in a
non-serialized object, so that was to leave the original object
being serialized unchanged.
On 9/6/2010 2:35 PM, Michael Bayer wrote:
On Sep 6, 2010, at 2:11 PM, Kent Bower wrote:
Also, I was hoping you would tell me whether this would be a candidate for
subclassing InstrumentedAttribute? Would that make more sense or providing custom
__getstate__& __setstate__ ?
__getstate__ / __setstate__ are pretty much what I like to use for pickle
stuff, unless some exotic situation makes me have to use __reduce__. One
problem with the recipe is that theres no 'deferred' loading of attributes.
So in that sense playing with InstrumentedAttribute would give you a chance to
put a callable in there that does what you want.
There is also the possibility that __setstate__ can load up callables into the
instance_state using state.set_callable(). This is a callable that triggers
when you access the attribute that is otherwise None. There's a little bit of
fanfare required to get that callable to assign to the attribute in the right
way. Attached is an example of that. This is all a little more shaky since
the state/callable API isn't really public. Hasn't changed for awhile but
there's no guarantee.
Thanks for your help, hopefully I'll be able to contribute such a recipe.
Kent
Since sqla won't load that for me in the case of transient, I need to load the
relation manually (unless you feel like enhancing that as well).
its not an enhancement - it was a broken behavior that was specifically
removed. The transient object has no session, so therefore no SQL can be
emitted - there's no context established.
Now I can manually emulate the obj being persistent with your changes for
On Sep 6, 2010, at 10:58 AM, Michael Bayer<mike...@zzzcomputing.com> wrote:
On Sep 6, 2010, at 9:06 AM, Kent wrote:
with_parent seems to add a join condition.
OK, so I guess you read the docs which is why you thought it joined and why you didn't
realize it doesn't work for transient. r20b6ce05f194 changes all that so that
with_parent() accepts transient objects and will do the "look at the
attributes" thing. The docs are updated as this method does use the lazy loader
SQL mechanism, not a join.
Is there a way to get at
the query object that would be rendered from a lazy load (or what
"subqueryload" would render on the subsequent load), but on a
transient object, if i supply the session?
even though not "recommended", can it make sqla believe my transient
object is detached by setting its state key?
There are reasons i do not want to add this to the session and
disabling autoflush would also cause problems.
On Sep 3, 9:58 am, Michael Bayer<mike...@zzzcomputing.com> wrote:
On Sep 3, 2010, at 9:36 AM, Kent wrote:
For the case of customerid = '7', that is a simple problem, but when
it is a more complex join condition, we only wanted to define this
condition in one single place in our application (namely, the orm).
That way, if or when that changes, developers don't need to search for
other places in the app that needed to manually duplicate the logic of
the orm join condition.
If I supplied the DBSession to sqla, it would know how to create the
proper Query object for this lazyload. Can you point me in the right
direction (even if where you point me is not currently part of the
public API)?
Query has the with_parent() method for this use case.
Thanks again,
Kent
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email tosqlalch...@googlegroups.com.
To unsubscribe from this group, send email
tosqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this
groupathttp://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 tosqlalch...@googlegroups.com.
To unsubscribe from this group, send email
tosqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group
athttp://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 tosqlalch...@googlegroups.com.
To unsubscribe from this group, send email
tosqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group
athttp://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 tosqlalch...@googlegroups.com.
To unsubscribe from this group, send email
tosqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group
athttp://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 tosqlalch...@googlegroups.com.
To unsubscribe from this group, send email
tosqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group
athttp://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 tosqlalch...@googlegroups.com.
To unsubscribe from this group, send email
tosqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group
athttp://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
sqlalchemy@googlegroups.com <mailto:sqlalchemy@googlegroups.com>.
To unsubscribe from this group, send email to
sqlalchemy+unsubscr...@googlegroups.com
<mailto: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.
--
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
<mailto:sqlalchemy@googlegroups.com>.
To unsubscribe from this group, send email to
sqlalchemy+unsubscr...@googlegroups.com
<mailto: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.
--
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
<mailto:sqlalchemy@googlegroups.com>.
To unsubscribe from this group, send email to
sqlalchemy+unsubscr...@googlegroups.com
<mailto: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.
--
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
<mailto:sqlalchemy@googlegroups.com>.
To unsubscribe from this group, send email to
sqlalchemy+unsubscr...@googlegroups.com
<mailto: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.
--
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.