diff --git a/django/db/migrations/state.py b/django/db/migrations/state.py index 6cf675d0e4..92716aa5d6 100644 --- a/django/db/migrations/state.py +++ b/django/db/migrations/state.py @@ -323,6 +323,16 @@ class ProjectState: for from_field_name in from_fields ] ) + # Fix field names (e.g. for CompositePrimaryKey) to refer to the + # new field. + if field_names := getattr(field, "field_names", None): + if old_name in field_names: + field.field_names = tuple( + [ + new_name if field_name == old_name else field_name + for field_name in field.field_names + ] + ) # Fix index/unique_together to refer to the new field. options = model_state.options for option in ("index_together", "unique_together"): diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index d95e382285..2ca8da31f7 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -3375,6 +3375,42 @@ class OperationTests(OperationTestBase): ) self.assertIndexExists("test_rnflit_pony", ["weight", "pink"]) + def test_rename_field_add_non_nullable_field_with_composite_pk(self): + app_label = "test_rnfafnnwcpk" + operations = [ + migrations.CreateModel( + name="Release", + fields=[ + ( + "pk", + models.CompositePrimaryKey("version", "name", primary_key=True), + ), + ("version", models.IntegerField()), + ("name", models.CharField(max_length=20)), + ], + ), + ] + project_state = self.apply_operations(app_label, ProjectState(), operations) + new_state = project_state.clone() + # Rename field used by CompositePrimaryKey. + operation = migrations.RenameField("Release", "name", "renamed_field") + operation.state_forwards(app_label, new_state) + with connection.schema_editor() as editor: + operation.database_forwards(app_label, editor, project_state, new_state) + self.assertColumnExists(f"{app_label}_release", "renamed_field") + project_state = new_state + new_state = new_state.clone() + # Add non-nullable field. Table is rebuilt on SQLite. + operation = migrations.AddField( + model_name="Release", + name="new_non_nullable_field", + field=models.CharField(default="x", max_length=20), + ) + operation.state_forwards(app_label, new_state) + with connection.schema_editor() as editor: + operation.database_forwards(app_label, editor, project_state, new_state) + self.assertColumnExists(f"{app_label}_release", "new_non_nullable_field") + def test_rename_field_with_db_column(self): project_state = self.apply_operations( "test_rfwdbc",