summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2024-03-26 22:58:47 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2024-03-26 22:59:23 +0100
commit345e3cf57f1e9bf870482cebf36b169d79ae63d2 (patch)
tree38b9652167e7c43f859729467121ba7c98bc722c
parent71368b6f00b44595115aac8e26811f42b5db77b7 (diff)
[5.0.x] Fixed #35329 -- Fixed migrations crash when adding partial unique constraints with nulls_distinct.
Bug in 595a2abb58e04caa4d55fb2589bb80fb2a8fdfa1. Thanks Lucas Lemke Saunitti for the report. Backport of b98271a6e42107233311d17f5d7bc74fbb47f22c from main
-rw-r--r--django/db/backends/base/schema.py2
-rw-r--r--docs/releases/5.0.4.txt4
-rw-r--r--tests/schema/tests.py32
3 files changed, 37 insertions, 1 deletions
diff --git a/django/db/backends/base/schema.py b/django/db/backends/base/schema.py
index d2c8c65979..86bf8b821a 100644
--- a/django/db/backends/base/schema.py
+++ b/django/db/backends/base/schema.py
@@ -129,7 +129,7 @@ class BaseDatabaseSchemaEditor:
)
sql_create_unique_index = (
"CREATE UNIQUE INDEX %(name)s ON %(table)s "
- "(%(columns)s)%(include)s%(condition)s%(nulls_distinct)s"
+ "(%(columns)s)%(include)s%(nulls_distinct)s%(condition)s"
)
sql_rename_index = "ALTER INDEX %(old_name)s RENAME TO %(new_name)s"
sql_delete_index = "DROP INDEX %(name)s"
diff --git a/docs/releases/5.0.4.txt b/docs/releases/5.0.4.txt
index 9b2fd6b170..6503f1ada3 100644
--- a/docs/releases/5.0.4.txt
+++ b/docs/releases/5.0.4.txt
@@ -17,3 +17,7 @@ Bugfixes
* Fixed a regression in Django 5.0 where the ``AdminFileWidget`` could be
rendered with two ``id`` attributes on the "Clear" checkbox
(:ticket:`35273`).
+
+* Fixed a bug in Django 5.0 that caused a migration crash on PostgreSQL 15+
+ when adding a partial ``UniqueConstraint`` with ``nulls_distinct``
+ (:ticket:`35329`).
diff --git a/tests/schema/tests.py b/tests/schema/tests.py
index 465245e3e7..fff4982315 100644
--- a/tests/schema/tests.py
+++ b/tests/schema/tests.py
@@ -3596,6 +3596,38 @@ class SchemaTests(TransactionTestCase):
constraints = self.get_constraints(Author._meta.db_table)
self.assertNotIn(constraint.name, constraints)
+ @skipUnlessDBFeature(
+ "supports_nulls_distinct_unique_constraints",
+ "supports_partial_indexes",
+ )
+ def test_unique_constraint_nulls_distinct_condition(self):
+ with connection.schema_editor() as editor:
+ editor.create_model(Author)
+ constraint = UniqueConstraint(
+ fields=["height", "weight"],
+ name="un_height_weight_start_A",
+ condition=Q(name__startswith="A"),
+ nulls_distinct=False,
+ )
+ with connection.schema_editor() as editor:
+ editor.add_constraint(Author, constraint)
+ Author.objects.create(name="Adam", height=None, weight=None)
+ Author.objects.create(name="Avocado", height=1, weight=None)
+ Author.objects.create(name="Adrian", height=None, weight=1)
+ with self.assertRaises(IntegrityError):
+ Author.objects.create(name="Alex", height=None, weight=None)
+ Author.objects.create(name="Bob", height=None, weight=None)
+ with self.assertRaises(IntegrityError):
+ Author.objects.create(name="Alex", height=1, weight=None)
+ Author.objects.create(name="Bill", height=None, weight=None)
+ with self.assertRaises(IntegrityError):
+ Author.objects.create(name="Alex", height=None, weight=1)
+ Author.objects.create(name="Celine", height=None, weight=1)
+ with connection.schema_editor() as editor:
+ editor.remove_constraint(Author, constraint)
+ constraints = self.get_constraints(Author._meta.db_table)
+ self.assertNotIn(constraint.name, constraints)
+
@skipIfDBFeature("supports_nulls_distinct_unique_constraints")
def test_unique_constraint_nulls_distinct_unsupported(self):
# UniqueConstraint is ignored on databases that don't support