On Sep 8, 2010, at 2:34 PM, Kent Bower wrote:

> 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

oh right.  We should add the same functionality to ClauseList then.  A testcase 
like test_lazy_relations->test_uses_get for composite keys should also be added.



> 
> 
> (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 to 
>>>>>>>>>>>>>>>>> sqlalch...@googlegroups.com.
>>>>>>>>>>>>>>>>> To unsubscribe from this group, send email to 
>>>>>>>>>>>>>>>>> sqlalchemy+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 
>>>>>>>>>>>>>>> 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.
>>>>>>>>>>>>>> 
>>>>>>>>>>>>> -- 
>>>>>>>>>>>>> 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.
>>>>>>>>>>>> 
>>>>>>>>>>> -- 
>>>>>>>>>>> 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.
>>>>>>>> 
>>>>>>>> -- 
>>>>>>>> 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.
>>>>>> 
>>>>>> -- 
>>>>>> 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.
>>>> 
>>>> -- 
>>>> 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.
>> 
>> -- 
>> 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.

-- 
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.

Reply via email to