From 338fc0e7f10f7ca781b059f2ff46e1a1a85c91f8 Mon Sep 17 00:00:00 2001
From: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Date: Wed, 1 Sep 2021 13:26:46 +0200
Subject: [PATCH] Fixed #33080 -- Preserved nullability of textual fields on
 Oracle.

Thanks Matt Hoskins for the report.
---
 django/db/backends/base/schema.py |  6 ++++--
 tests/schema/tests.py             | 21 +++++++++++++++++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py
index 15ccda52e2..896ea3d517 100644
--- a/django/db/backends/base/schema.py
+++ b/django/db/backends/base/schema.py
@@ -880,8 +880,10 @@ class BaseDatabaseSchemaEditor:
         Return a (sql, params) fragment to set a column to null or non-null
         as required by new_field, or None if no changes are required.
         """
-        if (self.connection.features.interprets_empty_strings_as_nulls and
-                new_field.get_internal_type() in ("CharField", "TextField")):
+        if (
+            self.connection.features.interprets_empty_strings_as_nulls and
+            new_field.empty_strings_allowed
+        ):
             # The field is nullable in the database anyway, leave it alone.
             return
         else:
diff --git a/tests/schema/tests.py b/tests/schema/tests.py
index 7dfad1b5d6..9e23c4608e 100644
--- a/tests/schema/tests.py
+++ b/tests/schema/tests.py
@@ -863,6 +863,27 @@ class SchemaTests(TransactionTestCase):
         with self.assertRaises(IntegrityError):
             Note.objects.create(info=None)
 
+    @skipUnlessDBFeature('interprets_empty_strings_as_nulls')
+    def test_alter_textual_field_not_null_to_null(self):
+        """
+        Nullability for textual fields is preserved on databases that
+        interpret empty strings as NULLs.
+        """
+        with connection.schema_editor() as editor:
+            editor.create_model(Author)
+        columns = self.column_classes(Author)
+        # Field is nullable.
+        self.assertTrue(columns['uuid'][1][6])
+        # Change to NOT NULL.
+        old_field = Author._meta.get_field('uuid')
+        new_field = SlugField(null=False, blank=True)
+        new_field.set_attributes_from_name('uuid')
+        with connection.schema_editor() as editor:
+            editor.alter_field(Author, old_field, new_field, strict=True)
+        columns = self.column_classes(Author)
+        # Nullability is preserved.
+        self.assertTrue(columns['uuid'][1][6])
+
     def test_alter_numeric_field_keep_null_status(self):
         """
         Changing a field type shouldn't affect the not null status.