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.