Commit 7737305a authored by Anssi Kääriäinen's avatar Anssi Kääriäinen
Browse files

Fixed #12886 -- aggregation over sliced queryset

parent 7d28bed1
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -313,14 +313,13 @@ class QuerySet(object):
            kwargs[arg.default_alias] = arg

        query = self.query.clone()

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

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

    def count(self):
        """
+4 −4
Original line number Diff line number Diff line
@@ -315,7 +315,7 @@ class Query(object):
            # Return value depends on the type of the field being processed.
            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.
        """
@@ -325,18 +325,18 @@ class Query(object):
        # If there is a group by clause, aggregating does not add useful
        # information but retrieves only the first row. Aggregate
        # 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
            query = AggregateQuery(self.model)

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

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

            try:
+8 −0
Original line number Diff line number Diff line
@@ -617,3 +617,11 @@ class BaseAggregateTestCase(TestCase):
        # Check internal state
        self.assertIsNone(annotated_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)