|
@@ -4,6 +4,7 @@ from datetime import datetime
|
|
|
from operator import attrgetter
|
|
|
|
|
|
from django.db.models import F
|
|
|
+from django.db.models.functions import Upper
|
|
|
from django.test import TestCase
|
|
|
|
|
|
from .models import Article, Author, Reference
|
|
@@ -17,8 +18,8 @@ class OrderingTests(TestCase):
|
|
|
cls.a2 = Article.objects.create(headline="Article 2", pub_date=datetime(2005, 7, 27))
|
|
|
cls.a3 = Article.objects.create(headline="Article 3", pub_date=datetime(2005, 7, 27))
|
|
|
cls.a4 = Article.objects.create(headline="Article 4", pub_date=datetime(2005, 7, 28))
|
|
|
- cls.author_1 = Author.objects.create()
|
|
|
- cls.author_2 = Author.objects.create()
|
|
|
+ cls.author_1 = Author.objects.create(name="Name 1")
|
|
|
+ cls.author_2 = Author.objects.create(name="Name 2")
|
|
|
for i in range(2):
|
|
|
Author.objects.create()
|
|
|
|
|
@@ -88,6 +89,53 @@ class OrderingTests(TestCase):
|
|
|
attrgetter("headline")
|
|
|
)
|
|
|
|
|
|
+ def test_order_by_nulls_first_and_last(self):
|
|
|
+ msg = "nulls_first and nulls_last are mutually exclusive"
|
|
|
+ with self.assertRaisesMessage(ValueError, msg):
|
|
|
+ Article.objects.order_by(F("author").desc(nulls_last=True, nulls_first=True))
|
|
|
+
|
|
|
+ def test_order_by_nulls_last(self):
|
|
|
+ Article.objects.filter(headline="Article 3").update(author=self.author_1)
|
|
|
+ Article.objects.filter(headline="Article 4").update(author=self.author_2)
|
|
|
+ # asc and desc are chainable with nulls_last.
|
|
|
+ self.assertSequenceEqual(
|
|
|
+ Article.objects.order_by(F("author").desc(nulls_last=True)),
|
|
|
+ [self.a4, self.a3, self.a1, self.a2],
|
|
|
+ )
|
|
|
+ self.assertSequenceEqual(
|
|
|
+ Article.objects.order_by(F("author").asc(nulls_last=True)),
|
|
|
+ [self.a3, self.a4, self.a1, self.a2],
|
|
|
+ )
|
|
|
+ self.assertSequenceEqual(
|
|
|
+ Article.objects.order_by(Upper("author__name").desc(nulls_last=True)),
|
|
|
+ [self.a4, self.a3, self.a1, self.a2],
|
|
|
+ )
|
|
|
+ self.assertSequenceEqual(
|
|
|
+ Article.objects.order_by(Upper("author__name").asc(nulls_last=True)),
|
|
|
+ [self.a3, self.a4, self.a1, self.a2],
|
|
|
+ )
|
|
|
+
|
|
|
+ def test_order_by_nulls_first(self):
|
|
|
+ Article.objects.filter(headline="Article 3").update(author=self.author_1)
|
|
|
+ Article.objects.filter(headline="Article 4").update(author=self.author_2)
|
|
|
+ # asc and desc are chainable with nulls_first.
|
|
|
+ self.assertSequenceEqual(
|
|
|
+ Article.objects.order_by(F("author").asc(nulls_first=True)),
|
|
|
+ [self.a1, self.a2, self.a3, self.a4],
|
|
|
+ )
|
|
|
+ self.assertSequenceEqual(
|
|
|
+ Article.objects.order_by(F("author").desc(nulls_first=True)),
|
|
|
+ [self.a1, self.a2, self.a4, self.a3],
|
|
|
+ )
|
|
|
+ self.assertSequenceEqual(
|
|
|
+ Article.objects.order_by(Upper("author__name").asc(nulls_first=True)),
|
|
|
+ [self.a1, self.a2, self.a3, self.a4],
|
|
|
+ )
|
|
|
+ self.assertSequenceEqual(
|
|
|
+ Article.objects.order_by(Upper("author__name").desc(nulls_first=True)),
|
|
|
+ [self.a1, self.a2, self.a4, self.a3],
|
|
|
+ )
|
|
|
+
|
|
|
def test_stop_slicing(self):
|
|
|
"""
|
|
|
Use the 'stop' part of slicing notation to limit the results.
|