From 325d7710ce9f6155bb55610ad6b4580d31263557 Mon Sep 17 00:00:00 2001 From: David Wobrock Date: Sat, 24 Jul 2021 08:17:39 +0200 Subject: [PATCH] Fixed #32743 -- Added foreign key altering when altering type of referenced primary key with MTI. --- django/db/backends/base/schema.py | 8 ++++- tests/migrations/test_operations.py | 51 +++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py index 8050441414..47fdae8fd4 100644 --- a/django/db/backends/base/schema.py +++ b/django/db/backends/base/schema.py @@ -36,10 +36,16 @@ def _all_related_fields(model): def _related_non_m2m_objects(old_field, new_field): # Filter out m2m objects from reverse relations. # Return (old_relation, new_relation) tuples. - return zip( + related_fields = zip( (obj for obj in _all_related_fields(old_field.model) if _is_relevant_relation(obj, old_field)), (obj for obj in _all_related_fields(new_field.model) if _is_relevant_relation(obj, new_field)), ) + for old_rel, new_rel in related_fields: + yield old_rel, new_rel + yield from _related_non_m2m_objects( + old_rel.remote_field, + new_rel.remote_field, + ) class BaseDatabaseSchemaEditor: diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index af9f371da6..84f1b89ba5 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -1505,6 +1505,57 @@ class OperationTests(OperationTestBase): operation.database_backwards("test_alflpkfk", editor, new_state, project_state) assertIdTypeEqualsFkType() + def test_alter_field_pk_mti_fk(self): + app_label = 'test_alflpkmtifk' + project_state = self.set_up_test_model(app_label, mti_model=True) + project_state = self.apply_operations(app_label, project_state, [ + migrations.CreateModel('ShetlandRider', fields=[ + ( + 'pony', + models.ForeignKey(f'{app_label}.ShetlandPony', models.CASCADE), + ), + ]), + ]) + operation = migrations.AlterField( + 'Pony', + 'id', + models.BigAutoField(primary_key=True), + ) + new_state = project_state.clone() + operation.state_forwards(app_label, new_state) + self.assertIsInstance( + new_state.models[app_label, 'pony'].fields['id'], + models.BigAutoField, + ) + + def _get_column_id_type(cursor, table, column): + return [ + c.type_code + for c in connection.introspection.get_table_description( + cursor, + f'{app_label}_{table}', + ) + if c.name == column + ][0] + + def assertIdTypeEqualsMTIFkType(): + with connection.cursor() as cursor: + parent_id_type = _get_column_id_type(cursor, 'pony', 'id') + child_id_type = _get_column_id_type(cursor, 'shetlandpony', 'pony_ptr_id') + mti_id_type = _get_column_id_type(cursor, 'shetlandrider', 'pony_id') + self.assertEqual(parent_id_type, child_id_type) + self.assertEqual(parent_id_type, mti_id_type) + + assertIdTypeEqualsMTIFkType() + # Alter primary key. + with connection.schema_editor() as editor: + operation.database_forwards(app_label, editor, project_state, new_state) + assertIdTypeEqualsMTIFkType() + # Reversal. + with connection.schema_editor() as editor: + operation.database_backwards(app_label, editor, new_state, project_state) + assertIdTypeEqualsMTIFkType() + @skipUnlessDBFeature('supports_foreign_keys') def test_alter_field_reloads_state_on_fk_with_to_field_target_type_change(self): app_label = 'test_alflrsfkwtflttc'