Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #10574 -- Documented interaction between annotations and order_by.

In the future, I'd like to fix this properly, but the current behavior
has the advantage of being consistent across the board (and changing it
everywhere is backwards-incompatible with documented functionality).

git-svn-id: http://code.djangoproject.com/svn/django/trunk@10172 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 6fa30faa797fd826b6c91aedd13a430430f11d35 1 parent 6828821
Malcolm Tredinnick authored March 25, 2009
2  docs/ref/models/querysets.txt
@@ -296,6 +296,8 @@ a model which defines a default ordering, or when using
296 296
 ordering was undefined prior to calling ``reverse()``, and will remain
297 297
 undefined afterward).
298 298
 
  299
+.. _querysets-distinct:
  300
+
299 301
 ``distinct()``
300 302
 ~~~~~~~~~~~~~~
301 303
 
51  docs/topics/db/aggregation.txt
@@ -315,6 +315,57 @@ will be automatically added to the result set. However, if the ``values()``
315 315
 clause is applied after the ``annotate()`` clause, you need to explicitly
316 316
 include the aggregate column.
317 317
 
  318
+Interaction with default ordering or ``order_by()``
  319
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  320
+
  321
+Fields that are mentioned in the ``order_by()`` part of a queryset (or which
  322
+are used in the default ordering on a model) are used when selecting the
  323
+output data, even if they are not otherwise specified in the ``values()``
  324
+call. These extra fields are used to group "like" results together and they
  325
+can make otherwise identical result rows appear to be separate. This shows up,
  326
+particularly, when counting things.
  327
+
  328
+By way of example, suppose you have a model like this::
  329
+
  330
+    class Item(models.Model):
  331
+        name = models.CharField(max_length=10)
  332
+        data = models.IntegerField()
  333
+
  334
+        class Meta:
  335
+            ordering = ["name"]
  336
+
  337
+The important part here is the default ordering on the ``name`` field. If you
  338
+want to count how many times each distinct ``data`` value appears, you might
  339
+try this::
  340
+
  341
+    # Warning: not quite correct!
  342
+    Item.objects.values("data").annotate(Count("id"))
  343
+
  344
+...which will group the ``Item`` objects by their common ``data`` values and
  345
+then count the number of ``id`` values in each group. Except that it won't
  346
+quite work. The default ordering by ``name`` will also play a part in the
  347
+grouping, so this query will group by distinct ``(data, name)`` pairs, which
  348
+isn't what you want. Instead, you should construct this queryset::
  349
+
  350
+    Item.objects.values("data").annotate(Count("id")).order_by()
  351
+
  352
+...clearing any ordering in the query. You could also order by, say, ``data``
  353
+without any harmful effects, since that is already playing a role in the
  354
+query.
  355
+
  356
+This behavior is the same as that noted in the queryset documentation for
  357
+:ref:`distinct() <querysets-distinct>` and the general rule is the same:
  358
+normally you won't want extra columns playing a part in the result, so clear
  359
+out the ordering, or at least make sure it's restricted only to those fields
  360
+you also select in a ``values()`` call.
  361
+
  362
+.. note::
  363
+    You might reasonably ask why Django doesn't remove the extraneous columns
  364
+    for you. The main reason is consistency with ``distinct()`` and other
  365
+    places: Django **never** removes ordering constraints that you have
  366
+    specified (and we can't change those other methods' behavior, as that
  367
+    would violate our :ref:`misc-api-stability` policy).
  368
+
318 369
 Aggregating annotations
319 370
 -----------------------
320 371
 

0 notes on commit 6fa30fa

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