1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Fixed #28335 -- Allowed query expressions in Meta.ordering.

This commit is contained in:
Dima Kudosh 2017-06-25 21:17:13 +03:00 committed by Tim Graham
parent 3d2c3905a6
commit 093fd479d6
5 changed files with 37 additions and 6 deletions

View File

@ -1553,8 +1553,8 @@ class Model(metaclass=ModelBase):
errors = [] errors = []
fields = cls._meta.ordering fields = cls._meta.ordering
# Skip '?' fields. # Skip expressions and '?' fields.
fields = (f for f in fields if f != '?') fields = (f for f in fields if isinstance(f, str) and f != '?')
# Convert "-field" to "field". # Convert "-field" to "field".
fields = ((f[1:] if f.startswith('-') else f) for f in fields) fields = ((f[1:] if f.startswith('-') else f) for f in fields)

View File

@ -256,9 +256,10 @@ Django quotes column and table names behind the scenes.
ordering = ['-order_date'] ordering = ['-order_date']
This is a tuple or list of strings. Each string is a field name with an optional This is a tuple or list of strings and/or query expressions. Each string is
"-" prefix, which indicates descending order. Fields without a leading "-" will a field name with an optional "-" prefix, which indicates descending order.
be ordered ascending. Use the string "?" to order randomly. 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:: 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'] 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 Default ordering also affects :ref:`aggregation queries
<aggregation-ordering-interaction>`. <aggregation-ordering-interaction>`.
.. versionchanged:: 2.0
Support for query expressions was added.
.. warning:: .. warning::
Ordering is not a free operation. Each field you add to the ordering Ordering is not a free operation. Each field you add to the ordering

View File

@ -283,6 +283,9 @@ Models
different conditionals <conditional-aggregation>` to multiple aggregations different conditionals <conditional-aggregation>` to multiple aggregations
over the same fields or relations. over the same fields or relations.
* Added support for expressions in :attr:`Meta.ordering
<django.db.models.Options.ordering>`.
Requests and Responses Requests and Responses
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~

View File

@ -42,6 +42,12 @@ class OrderedByAuthorArticle(Article):
ordering = ('author', 'second_author') ordering = ('author', 'second_author')
class OrderedByFArticle(Article):
class Meta:
proxy = True
ordering = (models.F('author').asc(nulls_first=True), 'id')
class Reference(models.Model): class Reference(models.Model):
article = models.ForeignKey(OrderedByAuthorArticle, models.CASCADE) article = models.ForeignKey(OrderedByAuthorArticle, models.CASCADE)

View File

@ -5,7 +5,7 @@ from django.db.models import F
from django.db.models.functions import Upper from django.db.models.functions import Upper
from django.test import TestCase from django.test import TestCase
from .models import Article, Author, Reference from .models import Article, Author, OrderedByFArticle, Reference
class OrderingTests(TestCase): class OrderingTests(TestCase):
@ -368,3 +368,13 @@ class OrderingTests(TestCase):
r1 = Reference.objects.create(article_id=self.a1.pk) r1 = Reference.objects.create(article_id=self.a1.pk)
r2 = Reference.objects.create(article_id=self.a2.pk) r2 = Reference.objects.create(article_id=self.a2.pk)
self.assertSequenceEqual(Reference.objects.all(), [r2, r1]) 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')
)