From 5220ca8d8a109721378e8d4c7f32e342c3a83af6 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Fri, 17 Apr 2020 00:54:37 -0400 Subject: [PATCH] Refs #30591 -- Adjusted table rebuild for non-pk relationship on SQLite. The existing code was only accounting for primary key changes and not all unique key fields that can be referenced. --- django/db/backends/sqlite3/schema.py | 22 ++++++++++++---------- tests/migrations/test_operations.py | 14 +++++++++++++- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/django/db/backends/sqlite3/schema.py b/django/db/backends/sqlite3/schema.py index 78d88c7dd9..aca5d61b39 100644 --- a/django/db/backends/sqlite3/schema.py +++ b/django/db/backends/sqlite3/schema.py @@ -358,8 +358,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): return self.execute(self._rename_field_sql(model._meta.db_table, old_field, new_field, new_type)) # Alter by remaking table self._remake_table(model, alter_field=(old_field, new_field)) - # 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: + # Rebuild tables with FKs pointing to this field. + if new_field.unique and old_type != new_type: related_models = set() opts = new_field.model._meta for remote_field in opts.related_objects: @@ -367,15 +367,17 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): 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: + if remote_field.field_name == new_field.name: + related_models.add(remote_field.related_model) + elif new_field.primary_key and 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) + if new_field.primary_key: + 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 051b8036b5..bb4b74e727 100644 --- a/tests/migrations/test_operations.py +++ b/tests/migrations/test_operations.py @@ -1341,7 +1341,7 @@ class OperationTests(OperationTestBase): project_state = self.apply_operations(app_label, ProjectState(), operations=[ migrations.CreateModel('Rider', fields=[ ('id', models.AutoField(primary_key=True)), - ('code', models.PositiveIntegerField(unique=True)), + ('code', models.IntegerField(unique=True)), ]), migrations.CreateModel('Pony', fields=[ ('id', models.AutoField(primary_key=True)), @@ -1354,6 +1354,18 @@ class OperationTests(OperationTestBase): models.CharField(max_length=100, unique=True), ) self.apply_operations(app_label, project_state, operations=[operation]) + id_type, id_null = [ + (c.type_code, c.null_ok) + for c in self.get_table_description('%s_rider' % app_label) + if c.name == 'code' + ][0] + fk_type, fk_null = [ + (c.type_code, c.null_ok) + for c in self.get_table_description('%s_pony' % app_label) + if c.name == 'rider_id' + ][0] + self.assertEqual(id_type, fk_type) + self.assertEqual(id_null, fk_null) @skipUnlessDBFeature('supports_foreign_keys') def test_alter_field_reloads_state_on_fk_with_to_field_related_name_target_type_change(self):