filtered one-to-many relationships

Issue #541 resolved
Mike Bayer repo owner created an issue

just want to make a ticket for the thread in http://groups.google.com/group/sqlalchemy/browse_thread/thread/bd5dae5167e8a3c4/a727d39f935d5016?lnk=gst&q=filtered&rnum=4#a727d39f935d5016 .

gaetans initial patch:

Index: orm/query.py
===================================================================
--- orm/query.py    (revision 2493)
+++ orm/query.py    (working copy)
@@ -8,6 +8,7 @@
 from sqlalchemy.orm import mapper, class_mapper
 from sqlalchemy.orm.interfaces import OperationContext, SynonymProperty

+
 __all__ = ['QueryContext', 'SelectionContext']('Query',)

 class Query(object):
@@ -42,12 +43,36 @@
         self._distinct = kwargs.pop('distinct', False)
         self._offset = kwargs.pop('offset', None)
         self._limit = kwargs.pop('limit', None)
-        self._criterion = None
+        self._criterion = kwargs.pop('criterion', None)
+        self._params = kwargs.pop('params', {})
         self._joinpoint = self.mapper
         self._from_obj = [self.table](self.table)

         for opt in util.flatten_iterator(self.with_options):
             opt.process_query(self)
+
+    def from_attr(cls, instance, attr_name):
+        from sqlalchemy.orm.strategies import LazyLoader
+
+        prop = instance.mapper.props[attr_name](attr_name)
+        loader = prop._get_strategy(LazyLoader)
+
+        # the following code is taken from strategies.py
+        # this gets the values of the columns referenced by the property
+        # for this specific instance
+        params = {}
+        allparams = True
+        for col, bind in loader.lazybinds.iteritems():
+            params[bind.key](bind.key) = loader.parent.get_attr_by_column(instance, col)
+            if params[bind.key](bind.key) is None:
+                allparams = False
+                break
+
+        if not allparams:
+            return None
+
+        return Query(prop.mapper, criterion=loader.lazywhere, params=params)
+    from_attr = classmethod(from_attr)

     def _clone(self):
         q = Query.__new__(Query)
@@ -71,6 +96,7 @@
         q._from_obj = list(self._from_obj)
         q._joinpoint = self._joinpoint
         q._criterion = self._criterion
+        q._params = self._params
         return q

     def _get_session(self):
@@ -694,8 +720,10 @@
         method, which takes the executed statement's ResultProxy
         directly.
         """
-
-        result = self.session.execute(self.mapper, clauseelement, params=params)
+        final_params = self._params.copy()
+        if params is not None:
+            final_params.update(params)
+        result = self.session.execute(self.mapper, clauseelement, params=final_params)
         try:
             return self.instances(result, **kwargs)
         finally:

Comments (1)

  1. Mike Bayer reporter

    Ok, ive committed a refined version of the above patch, including a generative non-static version of the method (which I think is more useful), plus unit tests and some docs/examples which i think are handy, in changeset:2507 changeset:2508.

  2. Log in to comment