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

[1.5.x] Fixed #21126 -- QuerySet value conversion failure

A .annotate().select_related() query resulted in misaligned rows vs
columns for compiler.resolve_columns() method.

Report & patch by Michael Manfre.

Backpatch of 83554b01 from master.
parent 43ab759c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -895,7 +895,7 @@ class BaseDatabaseOperations(object):
        Coerce the value returned by the database backend into a consistent type
        that is compatible with the field type.
        """
        if value is None:
        if value is None or field is None:
            return value
        internal_type = field.get_internal_type()
        if internal_type == 'FloatField':
+8 −2
Original line number Diff line number Diff line
@@ -774,6 +774,9 @@ class SQLCompiler(object):
            transaction.set_dirty(self.using)
        for rows in self.execute_sql(MULTI):
            for row in rows:
                if has_aggregate_select:
                    aggregate_start = len(self.query.extra_select) + len(self.query.select)
                    aggregate_end = aggregate_start + len(self.query.aggregate_select)
                if resolve_columns:
                    if fields is None:
                        # We only set this up here because
@@ -800,11 +803,14 @@ class SQLCompiler(object):
                            db_table = self.query.model._meta.db_table
                            fields = [f for f in fields if db_table in only_load and
                                      f.column in only_load[db_table]]
                        if has_aggregate_select:
                            # pad None in to fields for aggregates
                            fields = fields[:aggregate_start] + [
                                None for x in range(0, aggregate_end - aggregate_start)
                            ] + fields[aggregate_start:]
                    row = self.resolve_columns(row, fields)

                if has_aggregate_select:
                    aggregate_start = len(self.query.extra_select) + len(self.query.select)
                    aggregate_end = aggregate_start + len(self.query.aggregate_select)
                    row = tuple(row[:aggregate_start]) + tuple([
                        self.query.resolve_aggregate(value, aggregate, self.connection)
                        for (alias, aggregate), value
+11 −0
Original line number Diff line number Diff line
@@ -383,6 +383,17 @@ class AggregationTests(TestCase):
        qs = Entries.objects.annotate(clue_count=Count('clues__ID'))
        self.assertQuerysetEqual(qs, [])

    def test_boolean_conversion(self):
        # Aggregates mixed up ordering of columns for backend's convert_values
        # method. Refs #21126.
        e = Entries.objects.create(Entry='foo')
        c = Clues.objects.create(EntryID=e, Clue='bar')
        qs = Clues.objects.select_related('EntryID').annotate(Count('ID'))
        self.assertQuerysetEqual(
            qs, [c], lambda x: x)
        self.assertEqual(qs[0].EntryID, e)
        self.assertIs(qs[0].EntryID.Exclude, False)

    def test_empty(self):
        # Regression for #10089: Check handling of empty result sets with
        # aggregates