summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDima Kudosh <LagMegantic@yandex.ru>2017-06-25 21:17:13 +0300
committerTim Graham <timograham@gmail.com>2017-09-05 19:10:20 -0400
commit093fd479d6be1790c6dc174f9df3a895b50e8a2f (patch)
tree3829042666e7e74d62cc364363b4a18c29d86228
parent3d2c3905a606f373d1b4ad386ad8343112f384f7 (diff)
Fixed #28335 -- Allowed query expressions in Meta.ordering.
-rw-r--r--django/db/models/base.py4
-rw-r--r--docs/ref/models/options.txt18
-rw-r--r--docs/releases/2.0.txt3
-rw-r--r--tests/ordering/models.py6
-rw-r--r--tests/ordering/tests.py12
5 files changed, 37 insertions, 6 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index d39c0b9ea6..dd2ac1de8c 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -1553,8 +1553,8 @@ class Model(metaclass=ModelBase):
errors = []
fields = cls._meta.ordering
- # Skip '?' fields.
- fields = (f for f in fields if f != '?')
+ # Skip expressions and '?' fields.
+ fields = (f for f in fields if isinstance(f, str) and f != '?')
# Convert "-field" to "field".
fields = ((f[1:] if f.startswith('-') else f) for f in fields)
diff --git a/docs/ref/models/options.txt b/docs/ref/models/options.txt
index bf8cf10c33..33ff581d39 100644
--- a/docs/ref/models/options.txt
+++ b/docs/ref/models/options.txt
@@ -256,9 +256,10 @@ Django quotes column and table names behind the scenes.
ordering = ['-order_date']
- This is a tuple or list of strings. Each string is a field name with an optional
- "-" prefix, which indicates descending order. Fields without a leading "-" will
- be ordered ascending. Use the string "?" to order randomly.
+ This is a tuple or list of strings and/or query expressions. Each string is
+ a field name with an optional "-" prefix, which indicates descending order.
+ Fields without a leading "-" will be ordered ascending. Use the string "?"
+ to order randomly.
For example, to order by a ``pub_date`` field ascending, use this::
@@ -272,9 +273,20 @@ Django quotes column and table names behind the scenes.
ordering = ['-pub_date', 'author']
+ You can also use :doc:`query expressions </ref/models/expressions>`. To
+ order by ``author`` ascending and make null values sort last, use this::
+
+ from django.db.models import F
+
+ ordering = [F('author').asc(nulls_last=True)]
+
Default ordering also affects :ref:`aggregation queries
<aggregation-ordering-interaction>`.
+ .. versionchanged:: 2.0
+
+ Support for query expressions was added.
+
.. warning::
Ordering is not a free operation. Each field you add to the ordering
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index 4f92927c1e..a8530d11c2 100644
--- a/docs/releases/2.0.txt
+++ b/docs/releases/2.0.txt
@@ -283,6 +283,9 @@ Models
different conditionals <conditional-aggregation>` to multiple aggregations
over the same fields or relations.
+* Added support for expressions in :attr:`Meta.ordering
+ <django.db.models.Options.ordering>`.
+
Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~
diff --git a/tests/ordering/models.py b/tests/ordering/models.py
index d3024f5fc0..85e8c59bb6 100644
--- a/tests/ordering/models.py
+++ b/tests/ordering/models.py
@@ -42,6 +42,12 @@ class OrderedByAuthorArticle(Article):
ordering = ('author', 'second_author')
+class OrderedByFArticle(Article):
+ class Meta:
+ proxy = True
+ ordering = (models.F('author').asc(nulls_first=True), 'id')
+
+
class Reference(models.Model):
article = models.ForeignKey(OrderedByAuthorArticle, models.CASCADE)
diff --git a/tests/ordering/tests.py b/tests/ordering/tests.py
index ff749331b9..dbc924b06b 100644
--- a/tests/ordering/tests.py
+++ b/tests/ordering/tests.py
@@ -5,7 +5,7 @@ from django.db.models import F
from django.db.models.functions import Upper
from django.test import TestCase
-from .models import Article, Author, Reference
+from .models import Article, Author, OrderedByFArticle, Reference
class OrderingTests(TestCase):
@@ -368,3 +368,13 @@ class OrderingTests(TestCase):
r1 = Reference.objects.create(article_id=self.a1.pk)
r2 = Reference.objects.create(article_id=self.a2.pk)
self.assertSequenceEqual(Reference.objects.all(), [r2, r1])
+
+ def test_default_ordering_by_f_expression(self):
+ """F expressions can be used in Meta.ordering."""
+ articles = OrderedByFArticle.objects.all()
+ articles.filter(headline='Article 2').update(author=self.author_2)
+ articles.filter(headline='Article 3').update(author=self.author_1)
+ self.assertQuerysetEqual(
+ articles, ['Article 1', 'Article 4', 'Article 3', 'Article 2'],
+ attrgetter('headline')
+ )