From 9f07f27124540e27b4c3140235da375b974c4175 Mon Sep 17 00:00:00 2001
From: Simon Charette <charette.s@gmail.com>
Date: Tue, 17 Mar 2020 22:00:28 -0400
Subject: [PATCH] Fixed #31376 -- Optimized nulls ordering when possible on
 SQLite and MySQL.

Both backends order NULLs first on ascending ordering and last on
descending ordering which makes ORDER BY IS (NOT)? NULL wasteful when
asc(nulls_first) and desc(nulls_last) are used since it prevents indice
usage.
---
 django/db/backends/base/features.py    | 3 +++
 django/db/backends/mysql/features.py   | 1 +
 django/db/backends/sqlite3/features.py | 1 +
 django/db/models/expressions.py        | 8 ++++++--
 4 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py
index 5760b59098..c2b92ecdee 100644
--- a/django/db/backends/base/features.py
+++ b/django/db/backends/base/features.py
@@ -91,6 +91,9 @@ class BaseDatabaseFeatures:
     # Does the backend support NULLS FIRST and NULLS LAST in ORDER BY?
     supports_order_by_nulls_modifier = True
 
+    # Does the backend orders NULLS FIRST by default?
+    order_by_nulls_first = False
+
     # The database's limit on the number of query parameters.
     max_query_params = None
 
diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py
index 1d0cd365db..e1d4ce726b 100644
--- a/django/db/backends/mysql/features.py
+++ b/django/db/backends/mysql/features.py
@@ -51,6 +51,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     # Neither MySQL nor MariaDB support partial indexes.
     supports_partial_indexes = False
     supports_order_by_nulls_modifier = False
+    order_by_nulls_first = True
 
     @cached_property
     def _mysql_storage_engine(self):
diff --git a/django/db/backends/sqlite3/features.py b/django/db/backends/sqlite3/features.py
index 6aebbc3262..84eca98644 100644
--- a/django/db/backends/sqlite3/features.py
+++ b/django/db/backends/sqlite3/features.py
@@ -45,3 +45,4 @@ class DatabaseFeatures(BaseDatabaseFeatures):
     supports_frame_range_fixed_distance = Database.sqlite_version_info >= (3, 28, 0)
     supports_aggregate_filter_clause = Database.sqlite_version_info >= (3, 30, 1)
     supports_order_by_nulls_modifier = Database.sqlite_version_info >= (3, 30, 0)
+    order_by_nulls_first = True
diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index f773e99a0f..84960d77e1 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -1120,9 +1120,13 @@ class OrderBy(BaseExpression):
             elif self.nulls_first:
                 template = '%s NULLS FIRST' % template
         else:
-            if self.nulls_last:
+            if self.nulls_last and not (
+                self.descending and connection.features.order_by_nulls_first
+            ):
                 template = '%%(expression)s IS NULL, %s' % template
-            elif self.nulls_first:
+            elif self.nulls_first and not (
+                not self.descending and connection.features.order_by_nulls_first
+            ):
                 template = '%%(expression)s IS NOT NULL, %s' % template
         connection.ops.check_expression_support(self)
         expression_sql, params = compiler.compile(self.expression)