summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorMatthew Wilkes <git@matthewwilkes.name>2017-06-18 16:53:40 +0100
committerTim Graham <timograham@gmail.com>2018-02-10 19:08:55 -0500
commit2162f0983de0dfe2178531638ce7ea56f54dd4e7 (patch)
treebb1e859159200fa7ebeeaa02ec3908e1cf5d2655 /docs
parentbf26f66029bca94b007a2452679ac004598364a6 (diff)
Fixed #24747 -- Allowed transforms in QuerySet.order_by() and distinct(*fields).
Diffstat (limited to 'docs')
-rw-r--r--docs/howto/custom-lookups.txt15
-rw-r--r--docs/ref/models/expressions.txt8
-rw-r--r--docs/ref/models/querysets.txt32
-rw-r--r--docs/releases/2.1.txt6
4 files changed, 59 insertions, 2 deletions
diff --git a/docs/howto/custom-lookups.txt b/docs/howto/custom-lookups.txt
index 32037a29aa..55fdc42237 100644
--- a/docs/howto/custom-lookups.txt
+++ b/docs/howto/custom-lookups.txt
@@ -138,6 +138,21 @@ SQL::
Note that in case there is no other lookup specified, Django interprets
``change__abs=27`` as ``change__abs__exact=27``.
+This also allows the result to be used in ``ORDER BY`` and ``DISTINCT ON``
+clauses. For example ``Experiment.objects.order_by('change__abs')`` generates::
+
+ SELECT ... ORDER BY ABS("experiments"."change") ASC
+
+And on databases that support distinct on fields (such as PostgreSQL),
+``Experiment.objects.distinct('change__abs')`` generates::
+
+ SELECT ... DISTINCT ON ABS("experiments"."change")
+
+.. versionchanged:: 2.1
+
+ Ordering and distinct support as described in the last two paragraphs was
+ added.
+
When looking for which lookups are allowable after the ``Transform`` has been
applied, Django uses the ``output_field`` attribute. We didn't need to specify
this here as it didn't change, but supposing we were applying ``AbsoluteValue``
diff --git a/docs/ref/models/expressions.txt b/docs/ref/models/expressions.txt
index 8ca975cc3a..70e3a58616 100644
--- a/docs/ref/models/expressions.txt
+++ b/docs/ref/models/expressions.txt
@@ -64,10 +64,14 @@ Some examples
# Aggregates can contain complex computations also
Company.objects.annotate(num_offerings=Count(F('products') + F('services')))
- # Expressions can also be used in order_by()
+ # Expressions can also be used in order_by(), either directly
Company.objects.order_by(Length('name').asc())
Company.objects.order_by(Length('name').desc())
-
+ # or using the double underscore lookup syntax.
+ from django.db.models import CharField
+ from django.db.models.functions import Length
+ CharField.register_lookup(Length)
+ Company.objects.order_by('name__length')
Built-in Expressions
====================
diff --git a/docs/ref/models/querysets.txt b/docs/ref/models/querysets.txt
index be07f0821d..2d6702beeb 100644
--- a/docs/ref/models/querysets.txt
+++ b/docs/ref/models/querysets.txt
@@ -535,6 +535,19 @@ The ``values()`` method also takes optional keyword arguments,
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>
+You can use built-in and :doc:`custom lookups </howto/custom-lookups>` in
+ordering. For example::
+
+ >>> from django.db.models import CharField
+ >>> from django.db.models.functions import Lower
+ >>> CharField.register_lookup(Lower, 'lower')
+ >>> Blog.objects.values('name__lower')
+ <QuerySet [{'name__lower': 'beatles blog'}]>
+
+.. versionchanged:: 2.1
+
+ Support for lookups was added.
+
An aggregate within a ``values()`` clause is applied before other arguments
within the same ``values()`` clause. If you need to group by another value,
add it to an earlier ``values()`` clause instead. For example::
@@ -580,6 +593,25 @@ A few subtleties that are worth mentioning:
* Calling :meth:`only()` and :meth:`defer()` after ``values()`` doesn't make
sense, so doing so will raise a ``NotImplementedError``.
+* Combining transforms and aggregates requires the use of two :meth:`annotate`
+ calls, either explicitly or as keyword arguments to :meth:`values`. As above,
+ if the transform has been registered on the relevant field type the first
+ :meth:`annotate` can be omitted, thus the following examples are equivalent::
+
+ >>> from django.db.models import CharField, Count
+ >>> from django.db.models.functions import Lower
+ >>> CharField.register_lookup(Lower, 'lower')
+ >>> Blog.objects.values('entry__authors__name__lower').annotate(entries=Count('entry'))
+ <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
+ >>> Blog.objects.values(
+ ... entry__authors__name__lower=Lower('entry__authors__name')
+ ... ).annotate(entries=Count('entry'))
+ <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
+ >>> Blog.objects.annotate(
+ ... entry__authors__name__lower=Lower('entry__authors__name')
+ ... ).values('entry__authors__name__lower').annotate(entries=Count('entry'))
+ <QuerySet [{'entry__authors__name__lower': 'test author', 'entries': 33}]>
+
It is useful when you know you're only going to need values from a small number
of the available fields and you won't need the functionality of a model
instance object. It's more efficient to select only the fields you need to use.
diff --git a/docs/releases/2.1.txt b/docs/releases/2.1.txt
index ae3dd67bc9..31252432bb 100644
--- a/docs/releases/2.1.txt
+++ b/docs/releases/2.1.txt
@@ -187,6 +187,9 @@ Models
* Query expressions can now be negated using a minus sign.
+* :meth:`.QuerySet.order_by` and :meth:`distinct(*fields) <.QuerySet.distinct>`
+ now support using field transforms.
+
Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~
@@ -242,6 +245,9 @@ Database backend API
* Renamed the ``allow_sliced_subqueries`` database feature flag to
``allow_sliced_subqueries_with_in``.
+* ``DatabaseOperations.distinct_sql()`` now requires an additional ``params``
+ argument and returns a tuple of SQL and parameters instead of a SQL string.
+
:mod:`django.contrib.gis`
-------------------------