From 760bb3a4c89be9711ab09975bcae09b168a6a45b Mon Sep 17 00:00:00 2001 From: DevilsAutumn Date: Wed, 1 May 2024 00:01:27 +0530 Subject: [PATCH] Added new feature flag to avoid recreation of fk constraints while dropping index. --- django/db/backends/base/features.py | 4 +++ django/db/backends/base/schema.py | 1 + django/db/backends/mysql/features.py | 1 + tests/schema/tests.py | 41 ++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/django/db/backends/base/features.py b/django/db/backends/base/features.py index ef874d74db..afaa9c992c 100644 --- a/django/db/backends/base/features.py +++ b/django/db/backends/base/features.py @@ -99,6 +99,10 @@ class BaseDatabaseFeatures: # Does the database have a copy of the zoneinfo database? has_zoneinfo_database = True + # Does the backend require the foreign key constraints to be recreated + # when dropping an index? + requires_fk_constraints_to_be_recreated = False + # When performing a GROUP BY, is an ORDER BY NULL required # to remove any ordering? requires_explicit_null_ordering_when_grouping = False diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py index 116c98f432..c0880efe49 100644 --- a/django/db/backends/base/schema.py +++ b/django/db/backends/base/schema.py @@ -919,6 +919,7 @@ class BaseDatabaseSchemaEditor: fks_dropped = set() if ( self.connection.features.supports_foreign_keys + and self.connection.features.requires_fk_constraints_to_be_recreated and old_field.remote_field and old_field.db_constraint and self._field_should_be_altered( diff --git a/django/db/backends/mysql/features.py b/django/db/backends/mysql/features.py index cafc6702eb..d810436092 100644 --- a/django/db/backends/mysql/features.py +++ b/django/db/backends/mysql/features.py @@ -15,6 +15,7 @@ class DatabaseFeatures(BaseDatabaseFeatures): supports_regex_backreferencing = False supports_date_lookup_using_string = False supports_timezones = False + requires_fk_constraints_to_be_recreated = True requires_explicit_null_ordering_when_grouping = True atomic_transactions = False can_clone_databases = True diff --git a/tests/schema/tests.py b/tests/schema/tests.py index 3a2947cf43..d00711d9f7 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -1745,6 +1745,47 @@ class SchemaTests(TransactionTestCase): editor.alter_field(LocalBook, old_field, new_field, strict=True) self.assertForeignKeyExists(LocalBook, "author_id", "schema_author") + @skipUnlessDBFeature("supports_foreign_keys") + def test_fk_constraint_index_drop(self): + with connection.schema_editor() as editor: + editor.create_model(Author) + editor.create_model(Book) + + author = Author.objects.create(name="Alice") + Book.objects.create( + author=author, + title="Much Ado About Foreign Keys", + pub_date=datetime.datetime.now(), + ) + + old_field = Book._meta.get_field("author") + new_field = ForeignKey(Author, CASCADE, db_index=False) + new_field.set_attributes_from_name("author") + with ( + CaptureQueriesContext(connection) as ctx, + connection.schema_editor() as editor, + ): + editor.alter_field(Book, old_field, new_field, strict=True) + + if connection.features.requires_fk_constraints_to_be_recreated: + self.assertIs( + any( + "DROP FOREIGN KEY" in query["sql"] for query in ctx.captured_queries + ), + True, + ) + self.assertIs( + any("ADD CONSTRAINT" in query["sql"] for query in ctx.captured_queries), + True, + ) + else: + self.assertIs( + any( + "DROP CONSTRAINT" in query["sql"] for query in ctx.captured_queries + ), + False, + ) + @skipUnlessDBFeature("supports_foreign_keys", "can_introspect_foreign_keys") def test_alter_o2o_to_fk(self): """