From a54828085732d5d2f020c2fb52fe1cbe1a20a6c9 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Fri, 17 Apr 2020 00:39:24 -0400 Subject: [PATCH] Fixed #31064 -- Recreated auto-created many-to-many tables on primary key data type change on SQLite. Both local and remote auto-created many-to-many relationships were affected. --- django/db/backends/sqlite3/schema.py | 11 ++++++++++- tests/migrations/test_operations.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/django/db/backends/sqlite3/schema.py b/django/db/backends/sqlite3/schema.py index d1b113f1b9..78d88c7dd9 100644 --- a/django/db/backends/sqlite3/schema.py +++ b/django/db/backends/sqlite3/schema.py @@ -361,12 +361,21 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): # Rebuild tables with FKs pointing to this field if the PK type changed. if old_field.primary_key and new_field.primary_key and old_type != new_type: related_models = set() - for remote_field in new_field.model._meta.related_objects: + opts = new_field.model._meta + for remote_field in opts.related_objects: # Ignore self-relationship since the table was already rebuilt. if remote_field.related_model == model: continue if not remote_field.many_to_many: related_models.add(remote_field.related_model) + elif remote_field.through._meta.auto_created: + related_models.add(remote_field.through) + for many_to_many in opts.many_to_many: + # Ignore self-relationship since the table was already rebuilt. + if many_to_many.related_model == model: + continue + if many_to_many.remote_field.through._meta.auto_created: + related_models.add(many_to_many.remote_field.through) for related_model in related_models: self._remake_table(related_model) diff --git a/tests/migrations/test_operations.py b/tests/migrations/test_operations.py index 162a14d529..051b8036b5 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -1275,6 +1275,16 @@ class OperationTests(OperationTestBase): Tests the AlterField operation on primary keys changes any FKs pointing to it. """ project_state = self.set_up_test_model("test_alflpkfk", related_model=True) + project_state = self.apply_operations('test_alflpkfk', project_state, [ + migrations.CreateModel('Stable', fields=[ + ('ponies', models.ManyToManyField('Pony')), + ]), + migrations.AddField( + 'Pony', + 'stables', + models.ManyToManyField('Stable'), + ), + ]) # Test the state alteration operation = migrations.AlterField("Pony", "id", models.FloatField(primary_key=True)) new_state = project_state.clone() @@ -1294,8 +1304,26 @@ class OperationTests(OperationTestBase): for c in connection.introspection.get_table_description(cursor, "test_alflpkfk_rider") if c.name == "pony_id" ][0] + m2m_fk_type, m2m_fk_null = [ + (c.type_code, c.null_ok) + for c in connection.introspection.get_table_description( + cursor, + 'test_alflpkfk_pony_stables', + ) if c.name == 'pony_id' + ][0] + remote_m2m_fk_type, remote_m2m_fk_null = [ + (c.type_code, c.null_ok) + for c in connection.introspection.get_table_description( + cursor, + 'test_alflpkfk_stable_ponies', + ) if c.name == 'pony_id' + ][0] self.assertEqual(id_type, fk_type) + self.assertEqual(id_type, m2m_fk_type) + self.assertEqual(id_type, remote_m2m_fk_type) self.assertEqual(id_null, fk_null) + self.assertEqual(id_null, m2m_fk_null) + self.assertEqual(id_null, remote_m2m_fk_null) assertIdTypeEqualsFkType() # Test the database alteration