Skip to content
This repository
Browse code

Full support for django-style querying with "DQ" object

  • Loading branch information...
commit 13e2f686ea723684424966991186b5d8ee00226b 1 parent 54821e4
Charles Leifer authored October 02, 2012

Showing 1 changed file with 48 additions and 25 deletions. Show diff stats Hide diff stats

  1. 73  peewee.py
73  peewee.py
@@ -169,6 +169,9 @@ def __init__(self, **query):
169 169
         self.query = query
170 170
         super(DQ, self).__init__()
171 171
 
  172
+    def clone(self):
  173
+        return DQ(**self.query)
  174
+
172 175
 
173 176
 class Expr(object):
174 177
     def __init__(self):
@@ -1064,24 +1067,6 @@ def clone_joins(self):
1064 1067
             (mc, list(j)) for mc, j in self._joins.items()
1065 1068
         )
1066 1069
 
1067  
-    def convert_dict_to_node(self, qdict):
1068  
-        node = Node(OP_AND)
1069  
-        joins = []
1070  
-        for key, value in sorted(qdict.items()):
1071  
-            curr = self.model_class
1072  
-            if '__' in key and key.rsplit('__', 1)[1] in DJANGO_MAP:
1073  
-                key, op = key.rsplit('__', 1)
1074  
-                op = DJANGO_MAP[op]
1075  
-            else:
1076  
-                op = OP_EQ
1077  
-            for piece in key.split('__'):
1078  
-                model_attr = getattr(curr, piece)
1079  
-                if isinstance(model_attr, (ForeignKeyField, ReverseRelationDescriptor)):
1080  
-                    curr = model_attr.rel_model
1081  
-                    joins.append(model_attr)
1082  
-            node &= Q(model_attr, op, value)
1083  
-        return node, joins
1084  
-
1085 1070
     @returns_clone
1086 1071
     def where(self, q_or_node):
1087 1072
         if self._where is None:
@@ -1228,13 +1213,51 @@ def ensure_join(self, lm, rm, on=None):
1228 1213
         query = self.switch(lm).join(rm, on=on).switch(ctx)
1229 1214
         return query
1230 1215
 
1231  
-    def filter(self, *dq, **query):
1232  
-        # plan:
1233  
-        # convert **query to a Node w/DQ as leaves
1234  
-        # then combine with the *dq and parse that node
1235  
-        node, joins = self.convert_dict_to_node(query)
  1216
+    def convert_dict_to_node(self, qdict):
  1217
+        accum = []
  1218
+        joins = []
  1219
+        for key, value in sorted(qdict.items()):
  1220
+            curr = self.model_class
  1221
+            if '__' in key and key.rsplit('__', 1)[1] in DJANGO_MAP:
  1222
+                key, op = key.rsplit('__', 1)
  1223
+                op = DJANGO_MAP[op]
  1224
+            else:
  1225
+                op = OP_EQ
  1226
+            for piece in key.split('__'):
  1227
+                model_attr = getattr(curr, piece)
  1228
+                if isinstance(model_attr, (ForeignKeyField, ReverseRelationDescriptor)):
  1229
+                    curr = model_attr.rel_model
  1230
+                    joins.append(model_attr)
  1231
+            accum.append(Q(model_attr, op, value))
  1232
+        return accum, joins
  1233
+
  1234
+    def filter(self, *args, **kwargs):
  1235
+        # normalize args and kwargs into a new node
  1236
+        dq_node = Node(OP_AND)
  1237
+        if kwargs:
  1238
+            dq_node &= DQ(**kwargs)
  1239
+        for arg in args:
  1240
+            dq_node &= arg.clone()
  1241
+
  1242
+        def _recurse(curr):
  1243
+            joins = []
  1244
+            accum = []
  1245
+            for child in curr.children:
  1246
+                if isinstance(child, Node):
  1247
+                    joins.extend(_recurse(child))
  1248
+                    accum.append(child)
  1249
+                elif isinstance(child, DQ):
  1250
+                    _a, _j = self.convert_dict_to_node(child.query)
  1251
+                    accum.extend(_a)
  1252
+                    joins.extend(_j)
  1253
+                else:
  1254
+                    accum.append(child)
  1255
+            curr.children = accum
  1256
+            return joins
  1257
+        dq_joins = _recurse(dq_node)
  1258
+
1236 1259
         query = self.clone()
1237  
-        for field in joins:
  1260
+        for field in dq_joins:
1238 1261
             if isinstance(field, ForeignKeyField):
1239 1262
                 lm, rm = field.model_class, field.rel_model
1240 1263
                 field_obj = field
@@ -1242,7 +1265,7 @@ def filter(self, *dq, **query):
1242 1265
                 lm, rm = field.field.rel_model, field.rel_model
1243 1266
                 field_obj = field.field
1244 1267
             query = query.ensure_join(lm, rm, field_obj)
1245  
-        return query.where(node)
  1268
+        return query.where(dq_node)
1246 1269
 
1247 1270
     def annotate(self, rel_model, annotation=None):
1248 1271
         annotation = annotation or fn.Count(rel_model._meta.primary_key).set_alias('count')

0 notes on commit 13e2f68

Please sign in to comment.
Something went wrong with that request. Please try again.