Fixed #32743 -- Added foreign key altering when altering type of referenced primary key with MTI.

This commit is contained in:
David Wobrock 2021-07-24 08:17:39 +02:00 committed by Mariusz Felisiak
parent f876c7d08e
commit 325d7710ce
2 changed files with 58 additions and 1 deletions

View File

@ -36,10 +36,16 @@ def _all_related_fields(model):
def _related_non_m2m_objects(old_field, new_field): def _related_non_m2m_objects(old_field, new_field):
# Filter out m2m objects from reverse relations. # Filter out m2m objects from reverse relations.
# Return (old_relation, new_relation) tuples. # 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(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)), (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: class BaseDatabaseSchemaEditor:

View File

@ -1505,6 +1505,57 @@ class OperationTests(OperationTestBase):
operation.database_backwards("test_alflpkfk", editor, new_state, project_state) operation.database_backwards("test_alflpkfk", editor, new_state, project_state)
assertIdTypeEqualsFkType() 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') @skipUnlessDBFeature('supports_foreign_keys')
def test_alter_field_reloads_state_on_fk_with_to_field_target_type_change(self): def test_alter_field_reloads_state_on_fk_with_to_field_target_type_change(self):
app_label = 'test_alflrsfkwtflttc' app_label = 'test_alflrsfkwtflttc'