Skip to content

Commit

Permalink
Fixed #12886 -- aggregation over sliced queryset
Browse files Browse the repository at this point in the history
  • Loading branch information
akaariai committed Aug 19, 2013
1 parent 7d28bed commit 7737305
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 7 deletions.
5 changes: 2 additions & 3 deletions django/db/models/query.py
Expand Up @@ -313,14 +313,13 @@ def aggregate(self, *args, **kwargs):
kwargs[arg.default_alias] = arg kwargs[arg.default_alias] = arg


query = self.query.clone() query = self.query.clone()

force_subq = query.low_mark != 0 or query.high_mark is not None
aggregate_names = [] aggregate_names = []
for (alias, aggregate_expr) in kwargs.items(): for (alias, aggregate_expr) in kwargs.items():
query.add_aggregate(aggregate_expr, self.model, alias, query.add_aggregate(aggregate_expr, self.model, alias,
is_summary=True) is_summary=True)
aggregate_names.append(alias) aggregate_names.append(alias)

return query.get_aggregation(using=self.db, force_subq=force_subq)
return query.get_aggregation(using=self.db)


def count(self): def count(self):
""" """
Expand Down
8 changes: 4 additions & 4 deletions django/db/models/sql/query.py
Expand Up @@ -315,7 +315,7 @@ def resolve_aggregate(self, value, aggregate, connection):
# Return value depends on the type of the field being processed. # Return value depends on the type of the field being processed.
return self.convert_values(value, aggregate.field, connection) return self.convert_values(value, aggregate.field, connection)


def get_aggregation(self, using): def get_aggregation(self, using, force_subq=False):
""" """
Returns the dictionary with the values of the existing aggregations. Returns the dictionary with the values of the existing aggregations.
""" """
Expand All @@ -325,18 +325,18 @@ def get_aggregation(self, using):
# If there is a group by clause, aggregating does not add useful # If there is a group by clause, aggregating does not add useful
# information but retrieves only the first row. Aggregate # information but retrieves only the first row. Aggregate
# over the subquery instead. # over the subquery instead.
if self.group_by is not None: if self.group_by is not None or force_subq:


from django.db.models.sql.subqueries import AggregateQuery from django.db.models.sql.subqueries import AggregateQuery
query = AggregateQuery(self.model) query = AggregateQuery(self.model)

obj = self.clone() obj = self.clone()
relabels = dict((t, 'subquery') for t in self.tables)


# Remove any aggregates marked for reduction from the subquery # Remove any aggregates marked for reduction from the subquery
# and move them to the outer AggregateQuery. # and move them to the outer AggregateQuery.
for alias, aggregate in self.aggregate_select.items(): for alias, aggregate in self.aggregate_select.items():
if aggregate.is_summary: if aggregate.is_summary:
query.aggregate_select[alias] = aggregate query.aggregate_select[alias] = aggregate.relabeled_clone(relabels)
del obj.aggregate_select[alias] del obj.aggregate_select[alias]


try: try:
Expand Down
8 changes: 8 additions & 0 deletions tests/aggregation/tests.py
Expand Up @@ -617,3 +617,11 @@ def test_ticket17424(self):
# Check internal state # Check internal state
self.assertIsNone(annotated_books.query.alias_map["aggregation_book"].join_type) self.assertIsNone(annotated_books.query.alias_map["aggregation_book"].join_type)
self.assertIsNone(excluded_books.query.alias_map["aggregation_book"].join_type) self.assertIsNone(excluded_books.query.alias_map["aggregation_book"].join_type)

def test_ticket12886(self):
"""
Check that aggregation over sliced queryset works correctly.
"""
qs = Book.objects.all().order_by('-rating')[0:3]
vals = qs.aggregate(average_top3_rating=Avg('rating'))['average_top3_rating']
self.assertAlmostEqual(vals, 4.5, places=2)

0 comments on commit 7737305

Please sign in to comment.