From 9159d173c3822312c653db7ff5b9a94b14af1dca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9F=C4=B1l=20Ulu=C5=9Fahin?= Date: Sun, 4 Oct 2020 13:24:20 +0100 Subject: [PATCH] Fixed #25253 -- Made AlterField operation a noop when changing attributes that don't affect the schema. --- django/db/backends/base/schema.py | 20 ++++++++++++++++++-- tests/schema/tests.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py index ccb41b2c61..9e5ceb9ec2 100644 --- a/django/db/backends/base/schema.py +++ b/django/db/backends/base/schema.py @@ -1063,9 +1063,25 @@ class BaseDatabaseSchemaEditor: _, new_path, new_args, new_kwargs = new_field.deconstruct() # Don't alter when: # - changing only a field name + # - changing an attribute that doesn't affect the schema # - adding only a db_column and the column name is not changed - old_kwargs.pop('db_column', None) - new_kwargs.pop('db_column', None) + non_database_attrs = [ + 'blank', + 'db_column', + 'editable', + 'error_messages', + 'help_text', + 'limit_choices_to', + # Database-level options are not supported, see #21961. + 'on_delete', + 'related_name', + 'related_query_name', + 'validators', + 'verbose_name', + ] + for attr in non_database_attrs: + old_kwargs.pop(attr, None) + new_kwargs.pop(attr, None) return ( self.quote_name(old_field.column) != self.quote_name(new_field.column) or (old_path, old_args, old_kwargs) != (new_path, new_args, new_kwargs) diff --git a/tests/schema/tests.py b/tests/schema/tests.py index 49fda069d3..e41db7a500 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -2758,6 +2758,35 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor, self.assertNumQueries(0): editor.alter_field(AuthorWithDefaultHeight, old_field, new_field, strict=True) + @skipUnlessDBFeature('supports_foreign_keys') + def test_alter_field_fk_attributes_noop(self): + """ + No queries are performed when changing field attributes that don't + affect the schema. + """ + with connection.schema_editor() as editor: + editor.create_model(Author) + editor.create_model(Book) + old_field = Book._meta.get_field('author') + new_field = ForeignKey( + Author, + blank=True, + editable=False, + error_messages={'invalid': 'error message'}, + help_text='help text', + limit_choices_to={'limit': 'choice'}, + on_delete=PROTECT, + related_name='related_name', + related_query_name='related_query_name', + validators=[lambda x: x], + verbose_name='verbose name', + ) + new_field.set_attributes_from_name('author') + with connection.schema_editor() as editor, self.assertNumQueries(0): + editor.alter_field(Book, old_field, new_field, strict=True) + with connection.schema_editor() as editor, self.assertNumQueries(0): + editor.alter_field(Book, new_field, old_field, strict=True) + def test_add_textfield_unhashable_default(self): # Create the table with connection.schema_editor() as editor: