From 28c98d41133802e4ddcf9d1994b93c69a802fc7a Mon Sep 17 00:00:00 2001
From: Allen Jonathan David <allenajdjonathan@gmail.com>
Date: Mon, 6 Dec 2021 14:17:22 +0530
Subject: [PATCH] Fixed #33216 -- Simpilified deconstructed paths for some
 expressions.

---
 django/db/models/expressions.py |  6 ++++++
 tests/expressions/tests.py      |  4 ++--
 tests/migrations/test_writer.py | 27 +++++++++++++++++++++++++++
 3 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/django/db/models/expressions.py b/django/db/models/expressions.py
index 8642e1f151..6f26dff0e0 100644
--- a/django/db/models/expressions.py
+++ b/django/db/models/expressions.py
@@ -651,6 +651,7 @@ class OuterRef(F):
         return self
 
 
+@deconstructible(path='django.db.models.Func')
 class Func(SQLiteNumericMixin, Expression):
     """An SQL function call."""
     function = None
@@ -731,6 +732,7 @@ class Func(SQLiteNumericMixin, Expression):
         return copy
 
 
+@deconstructible(path='django.db.models.Value')
 class Value(SQLiteNumericMixin, Expression):
     """Represent a wrapped value as a node within an expression."""
     # Provide a default value for `for_save` in order to allow unresolved
@@ -953,6 +955,7 @@ class OrderByList(Func):
         return super().as_sql(*args, **kwargs)
 
 
+@deconstructible(path='django.db.models.ExpressionWrapper')
 class ExpressionWrapper(SQLiteNumericMixin, Expression):
     """
     An expression that can wrap another expression so that it can provide
@@ -985,6 +988,7 @@ class ExpressionWrapper(SQLiteNumericMixin, Expression):
         return "{}({})".format(self.__class__.__name__, self.expression)
 
 
+@deconstructible(path='django.db.models.When')
 class When(Expression):
     template = 'WHEN %(condition)s THEN %(result)s'
     # This isn't a complete conditional expression, must be used in Case().
@@ -1052,6 +1056,7 @@ class When(Expression):
         return cols
 
 
+@deconstructible(path='django.db.models.Case')
 class Case(SQLiteNumericMixin, Expression):
     """
     An SQL searched CASE expression:
@@ -1225,6 +1230,7 @@ class Exists(Subquery):
         return sql, params
 
 
+@deconstructible(path='django.db.models.OrderBy')
 class OrderBy(Expression):
     template = '%(expression)s %(ordering)s'
     conditional = False
diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
index 9fd31d550c..06c9ad597a 100644
--- a/tests/expressions/tests.py
+++ b/tests/expressions/tests.py
@@ -1763,14 +1763,14 @@ class ValueTests(TestCase):
     def test_deconstruct(self):
         value = Value('name')
         path, args, kwargs = value.deconstruct()
-        self.assertEqual(path, 'django.db.models.expressions.Value')
+        self.assertEqual(path, 'django.db.models.Value')
         self.assertEqual(args, (value.value,))
         self.assertEqual(kwargs, {})
 
     def test_deconstruct_output_field(self):
         value = Value('name', output_field=CharField())
         path, args, kwargs = value.deconstruct()
-        self.assertEqual(path, 'django.db.models.expressions.Value')
+        self.assertEqual(path, 'django.db.models.Value')
         self.assertEqual(args, (value.value,))
         self.assertEqual(len(kwargs), 1)
         self.assertEqual(kwargs['output_field'].deconstruct(), CharField().deconstruct())
diff --git a/tests/migrations/test_writer.py b/tests/migrations/test_writer.py
index f21c560208..4506e6b541 100644
--- a/tests/migrations/test_writer.py
+++ b/tests/migrations/test_writer.py
@@ -607,6 +607,33 @@ class WriterTests(SimpleTestCase):
         with self.assertRaisesMessage(ValueError, "Could not find object EmailValidator2 in django.core.validators."):
             MigrationWriter.serialize(validator)
 
+    def test_serialize_complex_func_index(self):
+        index = models.Index(
+            models.Func('rating', function='ABS'),
+            models.Case(
+                models.When(name='special', then=models.Value('X')),
+                default=models.Value('other'),
+            ),
+            models.ExpressionWrapper(
+                models.F('pages'),
+                output_field=models.IntegerField(),
+            ),
+            models.OrderBy(models.F('name').desc()),
+            name='complex_func_index',
+        )
+        string, imports = MigrationWriter.serialize(index)
+        self.assertEqual(
+            string,
+            "models.Index(models.Func('rating', function='ABS'), "
+            "models.Case(models.When(name='special', then=models.Value('X')), "
+            "default=models.Value('other')), "
+            "models.ExpressionWrapper("
+            "models.F('pages'), output_field=models.IntegerField()), "
+            "models.OrderBy(models.OrderBy(models.F('name'), descending=True)), "
+            "name='complex_func_index')"
+        )
+        self.assertEqual(imports, {'from django.db import models'})
+
     def test_serialize_empty_nonempty_tuple(self):
         """
         Ticket #22679: makemigrations generates invalid code for (an empty