Răsfoiți Sursa

Fixed #34027 -- Fixed migrations crash when altering type of char/text fields referenced by foreign key on PostgreSQL.

David Sanders 2 ani în urmă
părinte
comite
9f8c994851
2 a modificat fișierele cu 53 adăugiri și 12 ștergeri
  1. 14 12
      django/db/backends/postgresql/schema.py
  2. 39 0
      tests/migrations/test_operations.py

+ 14 - 12
django/db/backends/postgresql/schema.py

@@ -131,6 +131,20 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
         return ""
 
     def _alter_column_type_sql(self, model, old_field, new_field, new_type):
+        # Drop indexes on varchar/text/citext columns that are changing to a
+        # different type.
+        old_db_params = old_field.db_parameters(connection=self.connection)
+        old_type = old_db_params["type"]
+        if (old_field.db_index or old_field.unique) and (
+            (old_type.startswith("varchar") and not new_type.startswith("varchar"))
+            or (old_type.startswith("text") and not new_type.startswith("text"))
+            or (old_type.startswith("citext") and not new_type.startswith("citext"))
+        ):
+            index_name = self._create_index_name(
+                model._meta.db_table, [old_field.column], suffix="_like"
+            )
+            self.execute(self._delete_index_sql(model, index_name))
+
         self.sql_alter_column_type = "ALTER COLUMN %(column)s TYPE %(type)s"
         # Cast when data type changed.
         if using_sql := self._using_sql(new_field, old_field):
@@ -227,18 +241,6 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
         new_db_params,
         strict=False,
     ):
-        # Drop indexes on varchar/text/citext columns that are changing to a
-        # different type.
-        if (old_field.db_index or old_field.unique) and (
-            (old_type.startswith("varchar") and not new_type.startswith("varchar"))
-            or (old_type.startswith("text") and not new_type.startswith("text"))
-            or (old_type.startswith("citext") and not new_type.startswith("citext"))
-        ):
-            index_name = self._create_index_name(
-                model._meta.db_table, [old_field.column], suffix="_like"
-            )
-            self.execute(self._delete_index_sql(model, index_name))
-
         super()._alter_field(
             model,
             old_field,

+ 39 - 0
tests/migrations/test_operations.py

@@ -2436,6 +2436,45 @@ class OperationTests(OperationTestBase):
             ],
         )
 
+    def test_alter_field_pk_fk_char_to_int(self):
+        app_label = "alter_field_pk_fk_char_to_int"
+        project_state = self.apply_operations(
+            app_label,
+            ProjectState(),
+            operations=[
+                migrations.CreateModel(
+                    name="Parent",
+                    fields=[
+                        ("id", models.CharField(max_length=255, primary_key=True)),
+                    ],
+                ),
+                migrations.CreateModel(
+                    name="Child",
+                    fields=[
+                        ("id", models.BigAutoField(primary_key=True)),
+                        (
+                            "parent",
+                            models.ForeignKey(
+                                f"{app_label}.Parent",
+                                on_delete=models.CASCADE,
+                            ),
+                        ),
+                    ],
+                ),
+            ],
+        )
+        self.apply_operations(
+            app_label,
+            project_state,
+            operations=[
+                migrations.AlterField(
+                    model_name="parent",
+                    name="id",
+                    field=models.BigIntegerField(primary_key=True),
+                ),
+            ],
+        )
+
     def test_rename_field_reloads_state_on_fk_target_changes(self):
         """
         If RenameField doesn't reload state appropriately, the AlterField