Commit 56dc22d6 authored by Alex Gaynor's avatar Alex Gaynor
Browse files

[1.2.X] Fixed a suite of errors in the ORM -- a) fixed calling...

[1.2.X] Fixed a suite of errors in the ORM -- a) fixed calling values_list().values_list() and changing whether the results are flat, b) fixed an issue with fields on the left-hand side of what becomes the HAVING clause not being included in the GROUP BY clause, and c) fixed a bug with fields from values() calls not being included in the GROUP BY clause.  This fixed the recent test failures under postgresql. Backport of [14715].

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14716 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent c8e9d35e
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -976,8 +976,7 @@ class ValuesListQuerySet(ValuesQuerySet):
            # If a field list has been specified, use it. Otherwise, use the
            # full list of fields, including extras and aggregates.
            if self._fields:
                fields = list(self._fields) + filter(lambda f: f not in self._fields,
                                                     aggregate_names)
                fields = list(self._fields) + filter(lambda f: f not in self._fields, aggregate_names)
            else:
                fields = names

@@ -987,6 +986,8 @@ class ValuesListQuerySet(ValuesQuerySet):

    def _clone(self, *args, **kwargs):
        clone = super(ValuesListQuerySet, self)._clone(*args, **kwargs)
        if not hasattr(clone, "flat"):
            # Only assign flat if the clone didn't already get it from kwargs
            clone.flat = self.flat
        return clone

+9 −5
Original line number Diff line number Diff line
@@ -466,9 +466,11 @@ class SQLCompiler(object):
        qn = self.quote_name_unless_alias
        result, params = [], []
        if self.query.group_by is not None:
            if len(self.query.model._meta.fields) == len(self.query.select) and \
                self.connection.features.allows_group_by_pk:
                self.query.group_by = [(self.query.model._meta.db_table, self.query.model._meta.pk.column)]
            if (len(self.query.model._meta.fields) == len(self.query.select) and
                self.connection.features.allows_group_by_pk):
                self.query.group_by = [
                    (self.query.model._meta.db_table, self.query.model._meta.pk.column)
                ]

            group_by = self.query.group_by or []

@@ -476,11 +478,13 @@ class SQLCompiler(object):
            for extra_select, extra_params in self.query.extra_select.itervalues():
                extra_selects.append(extra_select)
                params.extend(extra_params)
            for col in group_by + self.query.related_select_cols + extra_selects:
            cols = (group_by + self.query.select +
                self.query.related_select_cols + extra_selects)
            for col in cols:
                if isinstance(col, (list, tuple)):
                    result.append('%s.%s' % (qn(col[0]), qn(col[1])))
                elif hasattr(col, 'as_sql'):
                    result.append(col.as_sql(qn))
                    result.append(col.as_sql(qn, self.connection))
                else:
                    result.append('(%s)' % str(col))
        return result, params
+12 −2
Original line number Diff line number Diff line
@@ -195,8 +195,9 @@ class Query(object):
        Unpickling support.
        """
        # Rebuild list of field instances
        opts = obj_dict['model']._meta
        obj_dict['select_fields'] = [
            name is not None and obj_dict['model']._meta.get_field(name) or None
            name is not None and opts.get_field(name) or None
            for name in obj_dict['select_fields']
        ]

@@ -707,13 +708,20 @@ class Query(object):
        # "group by", "where" and "having".
        self.where.relabel_aliases(change_map)
        self.having.relabel_aliases(change_map)
        for columns in (self.select, self.aggregates.values(), self.group_by or []):
        for columns in [self.select, self.group_by or []]:
            for pos, col in enumerate(columns):
                if isinstance(col, (list, tuple)):
                    old_alias = col[0]
                    columns[pos] = (change_map.get(old_alias, old_alias), col[1])
                else:
                    col.relabel_aliases(change_map)
        for mapping in [self.aggregates]:
            for key, col in mapping.items():
                if isinstance(col, (list, tuple)):
                    old_alias = col[0]
                    mapping[key] = (change_map.get(old_alias, old_alias), col[1])
                else:
                    col.relabel_aliases(change_map)

        # 2. Rename the alias in the internal table/alias datastructures.
        for old_alias, new_alias in change_map.iteritems():
@@ -1075,6 +1083,8 @@ class Query(object):


        if having_clause:
            if (alias, col) not in self.group_by:
                self.group_by.append((alias, col))
            self.having.add((Constraint(alias, col, field), lookup_type, value),
                connector)
        else:
+1 −1
Original line number Diff line number Diff line
@@ -194,7 +194,7 @@ class DateQuery(Query):
        alias = result[3][-1]
        select = Date((alias, field.column), lookup_type)
        self.select = [select]
        self.select_fields = [None]
        self.select_fields = []
        self.select_related = False # See #7097.
        self.set_extra_mask([])
        self.distinct = True
+19 −0
Original line number Diff line number Diff line
@@ -675,6 +675,25 @@ class AggregationTests(TestCase):
            attrgetter("name")
        )

    def test_values_annotate_values(self):
        qs = Book.objects.values("name").annotate(
            n_authors=Count("authors")
        ).values_list("pk", flat=True)
        self.assertEqual(list(qs), list(Book.objects.values_list("pk", flat=True)))

    def test_having_group_by(self):
        # Test that when a field occurs on the LHS of a HAVING clause that it
        # appears correctly in the GROUP BY clause
        qs = Book.objects.values_list("name").annotate(
            n_authors=Count("authors")
        ).filter(
            pages__gt=F("n_authors")
        ).values_list("name", flat=True)
        # Results should be the same, all Books have more pages than authors
        self.assertEqual(
            list(qs), list(Book.objects.values_list("name", flat=True))
        )

    if run_stddev_tests():
        def test_stddev(self):
            self.assertEqual(
Loading