From 57d46606edd29880e7852a9ee86a77a96f4d0b3a Mon Sep 17 00:00:00 2001
From: Tomer Chachamu <tomer@festicket.com>
Date: Wed, 18 Oct 2017 14:09:45 +0100
Subject: [PATCH] [2.0.x] Fixed #28722 -- Made QuerySet.reverse() affect
 nulls_first/nulls_last.

Backport of 21a3a29dc9d138c248fd7922923b3ec710735c6c from master
---
 AUTHORS                         |  1 +
 django/db/models/expressions.py |  3 +++
 docs/releases/1.11.7.txt        |  3 +++
 tests/ordering/tests.py         | 36 ++++++++++++++++++---------------
 4 files changed, 27 insertions(+), 16 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index e877db3fda..7554f84576 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -790,6 +790,7 @@ answer newbie questions, and generally made Django that much better:
     Tomáš Kopeček <permonik@m6.cz>
     Tome Cvitan <tome@cvitan.com>
     Tomek Paczkowski <tomek@hauru.eu>
+    Tomer Chachamu
     Tommy Beadle <tbeadle@gmail.com>
     Tore Lundqvist <tore.lundqvist@gmail.com>
     torne-django@wolfpuppy.org.uk
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 49ca801924..bd64973623 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -1144,6 +1144,9 @@ class OrderBy(BaseExpression):
 
     def reverse_ordering(self):
         self.descending = not self.descending
+        if self.nulls_first or self.nulls_last:
+            self.nulls_first = not self.nulls_first
+            self.nulls_last = not self.nulls_last
         return self
 
     def asc(self):
diff --git a/docs/releases/1.11.7.txt b/docs/releases/1.11.7.txt
index 717174c625..fe2cf2e300 100644
--- a/docs/releases/1.11.7.txt
+++ b/docs/releases/1.11.7.txt
@@ -13,3 +13,6 @@ Bugfixes
   argument is a callable that returns ``None`` (:ticket:`28601`).
 
 * Fixed the Basque ``DATE_FORMAT`` string (:ticket:`28710`).
+
+* Made ``QuerySet.reverse()`` affect ``nulls_first`` and ``nulls_last``
+  (:ticket:`28722`).
diff --git a/tests/ordering/tests.py b/tests/ordering/tests.py
index dbc924b06b..07c319b4c3 100644
--- a/tests/ordering/tests.py
+++ b/tests/ordering/tests.py
@@ -92,24 +92,28 @@ class OrderingTests(TestCase):
         with self.assertRaisesMessage(ValueError, msg):
             Article.objects.order_by(F("author").desc(nulls_last=True, nulls_first=True))
 
+    def assertQuerysetEqualReversible(self, queryset, sequence):
+        self.assertSequenceEqual(queryset, sequence)
+        self.assertSequenceEqual(queryset.reverse(), list(reversed(sequence)))
+
     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.assertQuerysetEqualReversible(
+            Article.objects.order_by(F("author").desc(nulls_last=True), 'headline'),
             [self.a4, self.a3, self.a1, self.a2],
         )
-        self.assertSequenceEqual(
-            Article.objects.order_by(F("author").asc(nulls_last=True)),
+        self.assertQuerysetEqualReversible(
+            Article.objects.order_by(F("author").asc(nulls_last=True), 'headline'),
             [self.a3, self.a4, self.a1, self.a2],
         )
-        self.assertSequenceEqual(
-            Article.objects.order_by(Upper("author__name").desc(nulls_last=True)),
+        self.assertQuerysetEqualReversible(
+            Article.objects.order_by(Upper("author__name").desc(nulls_last=True), 'headline'),
             [self.a4, self.a3, self.a1, self.a2],
         )
-        self.assertSequenceEqual(
-            Article.objects.order_by(Upper("author__name").asc(nulls_last=True)),
+        self.assertQuerysetEqualReversible(
+            Article.objects.order_by(Upper("author__name").asc(nulls_last=True), 'headline'),
             [self.a3, self.a4, self.a1, self.a2],
         )
 
@@ -117,20 +121,20 @@ class OrderingTests(TestCase):
         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.assertQuerysetEqualReversible(
+            Article.objects.order_by(F("author").asc(nulls_first=True), 'headline'),
             [self.a1, self.a2, self.a3, self.a4],
         )
-        self.assertSequenceEqual(
-            Article.objects.order_by(F("author").desc(nulls_first=True)),
+        self.assertQuerysetEqualReversible(
+            Article.objects.order_by(F("author").desc(nulls_first=True), 'headline'),
             [self.a1, self.a2, self.a4, self.a3],
         )
-        self.assertSequenceEqual(
-            Article.objects.order_by(Upper("author__name").asc(nulls_first=True)),
+        self.assertQuerysetEqualReversible(
+            Article.objects.order_by(Upper("author__name").asc(nulls_first=True), 'headline'),
             [self.a1, self.a2, self.a3, self.a4],
         )
-        self.assertSequenceEqual(
-            Article.objects.order_by(Upper("author__name").desc(nulls_first=True)),
+        self.assertQuerysetEqualReversible(
+            Article.objects.order_by(Upper("author__name").desc(nulls_first=True), 'headline'),
             [self.a1, self.a2, self.a4, self.a3],
         )