From 8f04473af1da1ed4e8a07e89205da4e70d69b586 Mon Sep 17 00:00:00 2001 From: David Wobrock Date: Mon, 2 May 2022 14:43:35 +0200 Subject: [PATCH] Fixed #25105 -- Checked deferred constraints before updating rows on PostgreSQL. --- django/db/backends/postgresql/schema.py | 7 ++++++ tests/schema/tests.py | 32 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/django/db/backends/postgresql/schema.py b/django/db/backends/postgresql/schema.py index 3053c8d370..a22ae0094f 100644 --- a/django/db/backends/postgresql/schema.py +++ b/django/db/backends/postgresql/schema.py @@ -7,6 +7,13 @@ from django.db.backends.utils import strip_quotes class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): + # Setting all constraints to IMMEDIATE to allow changing data in the same + # transaction. + sql_update_with_default = ( + "UPDATE %(table)s SET %(column)s = %(default)s WHERE %(column)s IS NULL" + "; SET CONSTRAINTS ALL IMMEDIATE" + ) + sql_delete_sequence = "DROP SEQUENCE IF EXISTS %(sequence)s CASCADE" sql_create_index = ( diff --git a/tests/schema/tests.py b/tests/schema/tests.py index 2d12796cbd..fe717f8841 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -973,6 +973,38 @@ class SchemaTests(TransactionTestCase): Node.objects.update(parent=parent) editor.alter_field(Node, old_field, new_field, strict=True) + @isolate_apps("schema") + def test_alter_null_with_default_value_deferred_constraints(self): + class Publisher(Model): + class Meta: + app_label = "schema" + + class Article(Model): + publisher = ForeignKey(Publisher, CASCADE) + title = CharField(max_length=50, null=True) + description = CharField(max_length=100, null=True) + + class Meta: + app_label = "schema" + + with connection.schema_editor() as editor: + editor.create_model(Publisher) + editor.create_model(Article) + self.isolated_local_models = [Article, Publisher] + + publisher = Publisher.objects.create() + Article.objects.create(publisher=publisher) + + old_title = Article._meta.get_field("title") + new_title = CharField(max_length=50, null=False, default="") + new_title.set_attributes_from_name("title") + old_description = Article._meta.get_field("description") + new_description = CharField(max_length=100, null=False, default="") + new_description.set_attributes_from_name("description") + with connection.schema_editor() as editor: + editor.alter_field(Article, old_title, new_title, strict=True) + editor.alter_field(Article, old_description, new_description, strict=True) + def test_alter_text_field_to_date_field(self): """ #25002 - Test conversion of text field to date field.