Code

Ticket #6821: aggregate.diff

File aggregate.diff, 4.2 KB (added by Nicolas Lara <nicolaslara@…>, 6 years ago)

aggregate modifier 0.1

Line 
1Index: django/db/models/sql/query.py
2===================================================================
3--- django/db/models/sql/query.py       (revision 7274)
4+++ django/db/models/sql/query.py       (working copy)
5@@ -55,6 +55,7 @@
6         self.start_meta = None
7 
8         # SQL-related attributes
9+        self.aggregates = []
10         self.select = []
11         self.tables = []    # Aliases in the order they are created.
12         self.where = where()
13@@ -139,6 +140,7 @@
14         obj.standard_ordering = self.standard_ordering
15         obj.start_meta = self.start_meta
16         obj.select = self.select[:]
17+        obj.aggregates = self.aggregates[:]
18         obj.tables = self.tables[:]
19         obj.where = deepcopy(self.where)
20         obj.where_class = self.where_class
21@@ -171,6 +173,26 @@
22                     row = self.resolve_columns(row, fields)
23                 yield row
24 
25+    def get_aggregation(self):
26+        for field in self.select:
27+            self.group_by.append(field)
28+        self.select.extend(self.aggregates)
29+        self.aggregates = []
30+        #print self.as_sql()
31+        #print self.select
32+
33+        get_name = lambda x : isinstance(x, tuple) and x[1] or x.aliased_name
34+
35+        if self.group_by:
36+            data = self.execute_sql(MULTI)
37+            result = []
38+            for rs in data.next():
39+                result.append(dict(zip([get_name(i) for i in self.select], rs)))
40+            return result
41+        else:
42+            data = self.execute_sql(SINGLE)
43+            return dict(zip([get_name(i) for i in self.select], data))
44+           
45     def get_count(self):
46         """
47         Performs a COUNT() query using the current filter constraints.
48@@ -806,6 +828,37 @@
49             self.fill_related_selections(f.rel.to._meta, alias, cur_depth + 1,
50                     used, next, restricted)
51 
52+    def add_aggregate(self, aggregate_expr, aliased_name, model):
53+        """
54+        Adds a single aggregate expression to the Query
55+        """
56+        #TODO: Aliases, Joins
57+
58+        field_list = aggregate_expr.split(LOOKUP_SEP)
59+        aggregate_func = field_list.pop()
60+       
61+        opts = model._meta
62+
63+        field_name = field_list[0]
64+
65+        #if len(field_list) > 1:
66+        #    field, target, opts, join_list, last = self.setup_joins(
67+        #        field_list, opts, self.get_initial_alias(), False)
68+           
69+        #Review Aliases
70+        class AggregateNode:
71+            def __init__(self, field_name, aggregate_func, aliased_name):
72+                self.field_name = field_name
73+                self.aggregate_func = aggregate_func
74+                self.aliased_name = aliased_name
75+                self.alias = '' #get table alias
76+               
77+            def as_sql(self, quote_func=None):
78+                return '%s(%s)' % (self.aggregate_func.upper(),
79+                                   self.field_name)
80+
81+        self.aggregates.append(AggregateNode(field_name, aggregate_func, aliased_name))
82+       
83     def add_filter(self, filter_expr, connector=AND, negate=False, trim=False,
84             merge_negated=False):
85         """
86Index: django/db/models/query.py
87===================================================================
88--- django/db/models/query.py   (revision 7274)
89+++ django/db/models/query.py   (working copy)
90@@ -154,6 +154,17 @@
91                 setattr(obj, k, row[index_end + i])
92             yield obj
93 
94+    def aggregate(self, *args, **kwargs):
95+        """
96+        Returns the aggregation over the current model as values (or so it should).
97+        """
98+        if args:
99+            TypeError('Unexpected positional arguments')
100+           
101+        for (aggregate_expr, alias) in kwargs.items():
102+            self.query.add_aggregate(aggregate_expr, alias, self.model)
103+        return self.query.get_aggregation()
104+
105     def count(self):
106         """
107         Performs a SELECT COUNT() and returns the number of records as an
108@@ -328,7 +339,7 @@
109         Returns a new QuerySet that is a copy of the current one. This allows a
110         QuerySet to proxy for a model manager in some cases.
111         """
112-        return self._clone()
113+        return self._clone()       
114 
115     def filter(self, *args, **kwargs):
116         """