Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

queryset-refactor: Made sure the ordering columns in a distinct() que…

…ry 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
  • Loading branch information...
commit 4c4341f01289e66f084d295236274a2e4556ae0d 1 parent e9364c0
Malcolm Tredinnick authored October 15, 2007
26  django/db/models/sql/query.py
@@ -342,16 +342,22 @@ def get_columns(self):
342 342
         """
343 343
         qn = self.quote_name_unless_alias
344 344
         result = []
  345
+        aliases = []
345 346
         if self.select:
346 347
             for col in self.select:
347 348
                 if isinstance(col, (list, tuple)):
348  
-                    result.append('%s.%s' % (qn(col[0]), qn(col[1])))
  349
+                    r = '%s.%s' % (qn(col[0]), qn(col[1]))
  350
+                    result.append(r)
  351
+                    aliases.append(r)
349 352
                 else:
350 353
                     result.append(col.as_sql(quote_func=qn))
  354
+                    if hasattr(col, 'alias'):
  355
+                        aliases.append(col.alias)
351 356
         else:
352 357
             table_alias = self.tables[0]
353 358
             result = ['%s.%s' % (qn(table_alias), qn(f.column))
354 359
                     for f in self.model._meta.fields]
  360
+            aliases = result[:]
355 361
 
356 362
         # We sort extra_select so that the result columns are in a well-defined
357 363
         # order (and thus QuerySet.iterator can extract them correctly).
@@ -359,6 +365,9 @@ def get_columns(self):
359 365
         extra_select.sort()
360 366
         result.extend(['(%s) AS %s' % (col, alias)
361 367
                 for alias, col in extra_select])
  368
+        aliases.extend(self.extra_select.keys())
  369
+
  370
+        self._select_aliases = dict.fromkeys(aliases)
362 371
         return result
363 372
 
364 373
     def get_from_clause(self):
@@ -435,6 +444,8 @@ def get_ordering(self):
435 444
             # is handled in the previous test.
436 445
             ordering = self.order_by or self.model._meta.ordering
437 446
         qn = self.quote_name_unless_alias
  447
+        distinct = self.distinct
  448
+        select_aliases = self._select_aliases
438 449
         result = []
439 450
         for field in ordering:
440 451
             if field == '?':
@@ -454,17 +465,22 @@ def get_ordering(self):
454 465
                 # necessary.
455 466
                 col, order = get_order_dir(field)
456 467
                 table, col = col.split('.', 1)
457  
-                result.append('%s.%s %s' % (qn(self.table_alias(table)[0]), col,
458  
-                        order))
  468
+                elt = '%s.%s' % (qn(self.table_alias(table)[0]), col)
  469
+                if not distinct or elt in select_aliases:
  470
+                    result.append('%s %s' % (elt, order))
459 471
             elif get_order_dir(field)[0] not in self.extra_select:
460 472
                 # 'col' is of the form 'field' or 'field1__field2' or
461 473
                 # 'field1__field2__field', etc.
462 474
                 for table, col, order in self.find_ordering_name(field,
463 475
                         self.model._meta):
464  
-                    result.append('%s.%s %s' % (qn(table), qn(col), order))
  476
+                    elt = '%s.%s' % (qn(table), qn(col))
  477
+                    if not distinct or elt in select_aliases:
  478
+                        result.append('%s %s' % (elt, order))
465 479
             else:
466 480
                 col, order = get_order_dir(field)
467  
-                result.append('%s %s' % (qn(col), order))
  481
+                elt = qn(col)
  482
+                if not distinct or elt in select_aliases:
  483
+                    result.append('%s %s' % (elt, order))
468 484
         return result
469 485
 
470 486
     def find_ordering_name(self, name, opts, alias=None, default_order='ASC'):
11  tests/regressiontests/queries/models.py
@@ -14,6 +14,7 @@ def __unicode__(self):
14 14
 
15 15
 class Note(models.Model):
16 16
     note = models.CharField(maxlength=100)
  17
+    misc = models.CharField(maxlength=10)
17 18
 
18 19
     class Meta:
19 20
         ordering = ['note']
@@ -91,11 +92,11 @@ def __unicode__(self):
91 92
 >>> t5 = Tag(name='t5', parent=t3)
92 93
 >>> t5.save()
93 94
 
94  
->>> n1 = Note(note='n1')
  95
+>>> n1 = Note(note='n1', misc='foo')
95 96
 >>> n1.save()
96  
->>> n2 = Note(note='n2')
  97
+>>> n2 = Note(note='n2', misc='bar')
97 98
 >>> n2.save()
98  
->>> n3 = Note(note='n3')
  99
+>>> n3 = Note(note='n3', misc='foo')
99 100
 >>> n3.save()
100 101
 
101 102
 Create these out of order so that sorting by 'id' will be different to sorting
@@ -329,5 +330,9 @@ def __unicode__(self):
329 330
 Bug #3037
330 331
 >>> Item.objects.filter(Q(creator__name='a3', name='two')|Q(creator__name='a4', name='four'))
331 332
 [<Item: four>]
  333
+
  334
+Bug #5321
  335
+>>> Note.objects.values('misc').distinct().order_by('note', '-misc')
  336
+[{'misc': u'foo'}, {'misc': u'bar'}]
332 337
 """}
333 338
 

0 notes on commit 4c4341f

Please sign in to comment.
Something went wrong with that request. Please try again.