diff --git a/django/db/backends/postgresql/schema.py b/django/db/backends/postgresql/schema.py index 1afb85d468..bffa8bd45b 100644 --- a/django/db/backends/postgresql/schema.py +++ b/django/db/backends/postgresql/schema.py @@ -15,6 +15,10 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): sql_create_varchar_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s varchar_pattern_ops)%(extra)s" sql_create_text_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s text_pattern_ops)%(extra)s" + # Setting the constraint to IMMEDIATE runs any deferred checks to allow + # dropping it in the same transaction. + sql_delete_fk = "SET CONSTRAINTS %(name)s IMMEDIATE; ALTER TABLE %(table)s DROP CONSTRAINT %(name)s" + def quote_value(self, value): return psycopg2.extensions.adapt(value) diff --git a/tests/schema/tests.py b/tests/schema/tests.py index e8cb1996cb..cf96e4163e 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -532,6 +532,23 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field(Note, old_field, new_field, strict=True) + @skipUnlessDBFeature('can_defer_constraint_checks', 'can_rollback_ddl') + def test_alter_fk_checks_deferred_constraints(self): + """ + #25492 - Altering a foreign key's structure and data in the same + transaction. + """ + with connection.schema_editor() as editor: + editor.create_model(Node) + old_field = Node._meta.get_field('parent') + new_field = ForeignKey(Node, CASCADE) + new_field.set_attributes_from_name('parent') + parent = Node.objects.create() + with connection.schema_editor() as editor: + # Update the parent FK to create a deferred constraint check. + Node.objects.update(parent=parent) + editor.alter_field(Node, old_field, new_field, strict=True) + def test_alter_text_field_to_date_field(self): """ #25002 - Test conversion of text field to date field.