From d048f0d311cc9cb9578d687968f2d24a0a9efddb Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Tue, 16 Apr 2024 00:11:36 -0400 Subject: [PATCH] Fixed #35373 -- Fixed a crash when indexing a generated field on SQLite. Generated fields have to be excluded from the INSERT query against the remade table including the index. Thanks Moshe Dicker for the report, David Sanders and Mariusz Felisiak for the review. --- django/db/backends/sqlite3/schema.py | 4 +++- docs/releases/5.0.5.txt | 4 ++++ tests/schema/tests.py | 33 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/django/db/backends/sqlite3/schema.py b/django/db/backends/sqlite3/schema.py index 495714a894..c5b428fc67 100644 --- a/django/db/backends/sqlite3/schema.py +++ b/django/db/backends/sqlite3/schema.py @@ -150,6 +150,9 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): body.pop(old_field.name, None) mapping.pop(old_field.column, None) body[new_field.name] = new_field + rename_mapping[old_field.name] = new_field.name + if new_field.generated: + continue if old_field.null and not new_field.null: if new_field.db_default is NOT_PROVIDED: default = self.prepare_default(self.effective_default(new_field)) @@ -162,7 +165,6 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): mapping[new_field.column] = case_sql else: mapping[new_field.column] = self.quote_name(old_field.column) - rename_mapping[old_field.name] = new_field.name # Remove any deleted fields if delete_field: del body[delete_field.name] diff --git a/docs/releases/5.0.5.txt b/docs/releases/5.0.5.txt index f8b66a5999..788753c826 100644 --- a/docs/releases/5.0.5.txt +++ b/docs/releases/5.0.5.txt @@ -16,3 +16,7 @@ Bugfixes * Fixed a compatibility issue encountered in Python 3.11.9+ and 3.12.3+ when validating email max line lengths with content decoded using the ``surrogateescape`` error handling scheme (:ticket:`35361`). + +* Fixed a bug in Django 5.0 that caused a crash when applying migrations + including alterations to ``GeneratedField`` such as setting ``db_index=True`` + on SQLite (:ticket:`35373`). diff --git a/tests/schema/tests.py b/tests/schema/tests.py index ff126d446a..3a2947cf43 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -928,6 +928,39 @@ class SchemaTests(TransactionTestCase): self.assertEqual(obj.generated, "foo%") self.assertIs(obj.contains_foo, True) + @isolate_apps("schema") + @skipUnlessDBFeature("supports_stored_generated_columns") + def test_alter_generated_field(self): + class GeneratedFieldIndexedModel(Model): + number = IntegerField(default=1) + generated = GeneratedField( + expression=F("number"), + db_persist=True, + output_field=IntegerField(), + ) + + class Meta: + app_label = "schema" + + with connection.schema_editor() as editor: + editor.create_model(GeneratedFieldIndexedModel) + + old_field = GeneratedFieldIndexedModel._meta.get_field("generated") + new_field = GeneratedField( + expression=F("number"), + db_persist=True, + db_index=True, + output_field=IntegerField(), + ) + new_field.contribute_to_class(GeneratedFieldIndexedModel, "generated") + + with connection.schema_editor() as editor: + editor.alter_field(GeneratedFieldIndexedModel, old_field, new_field) + + self.assertIn( + "generated", self.get_indexes(GeneratedFieldIndexedModel._meta.db_table) + ) + @isolate_apps("schema") def test_add_auto_field(self): class AddAutoFieldModel(Model):