mirror of
https://github.com/django/django.git
synced 2025-07-07 11:19:12 +00:00
[4.0.x] Fixed #33462 -- Fixed migration crash when altering type of primary key with MTI and foreign key.
This prevents duplicated operations when altering type of primary key with MTI and foreign key. Previously, a foreign key to the base model was added twice, once directly and once by the inheritance model. Thanks bcail for the report. Regression in 325d7710ce9f6155bb55610ad6b4580d31263557. Backport of e972620ada4f9ed7bc57f28e133e85c85b0a7b20 from main
This commit is contained in:
parent
f4de87038e
commit
7c2d4d943b
@ -30,7 +30,9 @@ def _is_relevant_relation(relation, altered_field):
|
||||
|
||||
|
||||
def _all_related_fields(model):
|
||||
return model._meta._get_fields(forward=False, reverse=True, include_hidden=True)
|
||||
return model._meta._get_fields(
|
||||
forward=False, reverse=True, include_hidden=True, include_parents=False,
|
||||
)
|
||||
|
||||
|
||||
def _related_non_m2m_objects(old_field, new_field):
|
||||
|
@ -28,3 +28,7 @@ Bugfixes
|
||||
|
||||
* Fixed a regression in Django 4.0 that caused incorrect
|
||||
:attr:`.ModelAdmin.radio_fields` layout in the admin (:ticket:`33407`).
|
||||
|
||||
* Fixed a duplicate operation regression in Django 4.0 that caused a migration
|
||||
crash when altering a primary key type for a concrete parent model referenced
|
||||
by a foreign key (:ticket:`33462`).
|
||||
|
@ -1600,6 +1600,73 @@ class OperationTests(OperationTestBase):
|
||||
(f'{app_label}_shetlandpony', 'pony_ptr_id'),
|
||||
)
|
||||
|
||||
def test_alter_field_pk_mti_and_fk_to_base(self):
|
||||
app_label = 'test_alflpkmtiftb'
|
||||
project_state = self.set_up_test_model(
|
||||
app_label, mti_model=True, related_model=True,
|
||||
)
|
||||
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')
|
||||
fk_id_type = _get_column_id_type(cursor, 'rider', 'pony_id')
|
||||
child_id_type = _get_column_id_type(cursor, 'shetlandpony', 'pony_ptr_id')
|
||||
self.assertEqual(parent_id_type, child_id_type)
|
||||
self.assertEqual(parent_id_type, fk_id_type)
|
||||
|
||||
assertIdTypeEqualsMTIFkType()
|
||||
# Alter primary key.
|
||||
with connection.schema_editor() as editor:
|
||||
operation.database_forwards(app_label, editor, project_state, new_state)
|
||||
assertIdTypeEqualsMTIFkType()
|
||||
if connection.features.supports_foreign_keys:
|
||||
self.assertFKExists(
|
||||
f'{app_label}_shetlandpony',
|
||||
['pony_ptr_id'],
|
||||
(f'{app_label}_pony', 'id'),
|
||||
)
|
||||
self.assertFKExists(
|
||||
f'{app_label}_rider',
|
||||
['pony_id'],
|
||||
(f'{app_label}_pony', 'id'),
|
||||
)
|
||||
# Reversal.
|
||||
with connection.schema_editor() as editor:
|
||||
operation.database_backwards(app_label, editor, new_state, project_state)
|
||||
assertIdTypeEqualsMTIFkType()
|
||||
if connection.features.supports_foreign_keys:
|
||||
self.assertFKExists(
|
||||
f'{app_label}_shetlandpony',
|
||||
['pony_ptr_id'],
|
||||
(f'{app_label}_pony', 'id'),
|
||||
)
|
||||
self.assertFKExists(
|
||||
f'{app_label}_rider',
|
||||
['pony_id'],
|
||||
(f'{app_label}_pony', 'id'),
|
||||
)
|
||||
|
||||
@skipUnlessDBFeature('supports_foreign_keys')
|
||||
def test_alter_field_reloads_state_on_fk_with_to_field_target_type_change(self):
|
||||
app_label = 'test_alflrsfkwtflttc'
|
||||
|
Loading…
x
Reference in New Issue
Block a user