diff options
| author | Malcolm Tredinnick <malcolm.tredinnick@gmail.com> | 2007-10-15 01:20:10 +0000 |
|---|---|---|
| committer | Malcolm Tredinnick <malcolm.tredinnick@gmail.com> | 2007-10-15 01:20:10 +0000 |
| commit | 4c4341f01289e66f084d295236274a2e4556ae0d (patch) | |
| tree | 9ab906748713789400f3ef555bd42717b6c037ac | |
| parent | e9364c06d6be32dc37e09620105e970472587d87 (diff) | |
queryset-refactor: Made sure the ordering columns in a distinct() query only
include the columns we are selecting on. This avoids some PostgreSQL problems
and leads to more efficient queries to boot. Refs #5321.
git-svn-id: http://code.djangoproject.com/svn/django/branches/queryset-refactor@6515 bcc190cf-cafb-0310-a4f2-bffc1f526a37
| -rw-r--r-- | django/db/models/sql/query.py | 26 | ||||
| -rw-r--r-- | tests/regressiontests/queries/models.py | 11 |
2 files changed, 29 insertions, 8 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index 3c0e342c86..b7f346a632 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -342,16 +342,22 @@ class Query(object): """ qn = self.quote_name_unless_alias result = [] + aliases = [] if self.select: for col in self.select: if isinstance(col, (list, tuple)): - result.append('%s.%s' % (qn(col[0]), qn(col[1]))) + r = '%s.%s' % (qn(col[0]), qn(col[1])) + result.append(r) + aliases.append(r) else: result.append(col.as_sql(quote_func=qn)) + if hasattr(col, 'alias'): + aliases.append(col.alias) else: table_alias = self.tables[0] result = ['%s.%s' % (qn(table_alias), qn(f.column)) for f in self.model._meta.fields] + aliases = result[:] # We sort extra_select so that the result columns are in a well-defined # order (and thus QuerySet.iterator can extract them correctly). @@ -359,6 +365,9 @@ class Query(object): extra_select.sort() result.extend(['(%s) AS %s' % (col, alias) for alias, col in extra_select]) + aliases.extend(self.extra_select.keys()) + + self._select_aliases = dict.fromkeys(aliases) return result def get_from_clause(self): @@ -435,6 +444,8 @@ class Query(object): # is handled in the previous test. ordering = self.order_by or self.model._meta.ordering qn = self.quote_name_unless_alias + distinct = self.distinct + select_aliases = self._select_aliases result = [] for field in ordering: if field == '?': @@ -454,17 +465,22 @@ class Query(object): # necessary. col, order = get_order_dir(field) table, col = col.split('.', 1) - result.append('%s.%s %s' % (qn(self.table_alias(table)[0]), col, - order)) + elt = '%s.%s' % (qn(self.table_alias(table)[0]), col) + if not distinct or elt in select_aliases: + result.append('%s %s' % (elt, order)) elif get_order_dir(field)[0] not in self.extra_select: # 'col' is of the form 'field' or 'field1__field2' or # 'field1__field2__field', etc. for table, col, order in self.find_ordering_name(field, self.model._meta): - result.append('%s.%s %s' % (qn(table), qn(col), order)) + elt = '%s.%s' % (qn(table), qn(col)) + if not distinct or elt in select_aliases: + result.append('%s %s' % (elt, order)) else: col, order = get_order_dir(field) - result.append('%s %s' % (qn(col), order)) + elt = qn(col) + if not distinct or elt in select_aliases: + result.append('%s %s' % (elt, order)) return result def find_ordering_name(self, name, opts, alias=None, default_order='ASC'): diff --git a/tests/regressiontests/queries/models.py b/tests/regressiontests/queries/models.py index 048ced9543..9b076633c7 100644 --- a/tests/regressiontests/queries/models.py +++ b/tests/regressiontests/queries/models.py @@ -14,6 +14,7 @@ class Tag(models.Model): class Note(models.Model): note = models.CharField(maxlength=100) + misc = models.CharField(maxlength=10) class Meta: ordering = ['note'] @@ -91,11 +92,11 @@ __test__ = {'API_TESTS':""" >>> t5 = Tag(name='t5', parent=t3) >>> t5.save() ->>> n1 = Note(note='n1') +>>> n1 = Note(note='n1', misc='foo') >>> n1.save() ->>> n2 = Note(note='n2') +>>> n2 = Note(note='n2', misc='bar') >>> n2.save() ->>> n3 = Note(note='n3') +>>> n3 = Note(note='n3', misc='foo') >>> n3.save() Create these out of order so that sorting by 'id' will be different to sorting @@ -329,5 +330,9 @@ Bugs #2874, #3002 Bug #3037 >>> Item.objects.filter(Q(creator__name='a3', name='two')|Q(creator__name='a4', name='four')) [<Item: four>] + +Bug #5321 +>>> Note.objects.values('misc').distinct().order_by('note', '-misc') +[{'misc': u'foo'}, {'misc': u'bar'}] """} |
