summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2023-01-26 09:31:40 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-01-26 09:34:15 +0100
commit26b7a25632e7fe0b897bc9b88b5c364a4b6398b6 (patch)
tree8ee9e441058e9a3c6218c3b323bc670d98ddc6e5
parentbc48c7dfd65dcfabbeb6aa5f0a5627038d2b7351 (diff)
[4.1.x] Fixed #34291 -- Fixed Meta.constraints validation crash on UniqueConstraint with ordered expressions.
Thanks Dan F for the report. Bug in 667105877e6723c6985399803a364848891513cc. Backport of 2b1242abb3989f5d74e787b09132d01bcbee5b55 from main.
-rw-r--r--django/db/models/constraints.py12
-rw-r--r--docs/releases/4.1.6.txt3
-rw-r--r--tests/constraints/tests.py23
3 files changed, 32 insertions, 6 deletions
diff --git a/django/db/models/constraints.py b/django/db/models/constraints.py
index 8cf1f0ff20..e623900574 100644
--- a/django/db/models/constraints.py
+++ b/django/db/models/constraints.py
@@ -2,7 +2,7 @@ from enum import Enum
from django.core.exceptions import FieldError, ValidationError
from django.db import connections
-from django.db.models.expressions import Exists, ExpressionList, F
+from django.db.models.expressions import Exists, ExpressionList, F, OrderBy
from django.db.models.indexes import IndexExpression
from django.db.models.lookups import Exact
from django.db.models.query_utils import Q
@@ -335,10 +335,12 @@ class UniqueConstraint(BaseConstraint):
replacement_map = instance._get_field_value_map(
meta=model._meta, exclude=exclude
)
- expressions = [
- Exact(expr, expr.replace_references(replacement_map))
- for expr in self.expressions
- ]
+ expressions = []
+ for expr in self.expressions:
+ # Ignore ordering.
+ if isinstance(expr, OrderBy):
+ expr = expr.expression
+ expressions.append(Exact(expr, expr.replace_references(replacement_map)))
queryset = queryset.filter(*expressions)
model_class_pk = instance._get_pk_val(model._meta)
if not instance._state.adding and model_class_pk is not None:
diff --git a/docs/releases/4.1.6.txt b/docs/releases/4.1.6.txt
index a581572a9a..e97c25aea0 100644
--- a/docs/releases/4.1.6.txt
+++ b/docs/releases/4.1.6.txt
@@ -10,4 +10,5 @@ in 4.1.5.
Bugfixes
========
-* ...
+* Fixed a bug in Django 4.1 that caused a crash of model validation on
+ ``UniqueConstraint`` with ordered expressions (:ticket:`34291`).
diff --git a/tests/constraints/tests.py b/tests/constraints/tests.py
index 5a498f0d73..223b4b3cd5 100644
--- a/tests/constraints/tests.py
+++ b/tests/constraints/tests.py
@@ -672,6 +672,29 @@ class UniqueConstraintTests(TestCase):
exclude={"name"},
)
+ def test_validate_ordered_expression(self):
+ constraint = models.UniqueConstraint(
+ Lower("name").desc(), name="name_lower_uniq_desc"
+ )
+ msg = "Constraint “name_lower_uniq_desc” is violated."
+ with self.assertRaisesMessage(ValidationError, msg):
+ constraint.validate(
+ UniqueConstraintProduct,
+ UniqueConstraintProduct(name=self.p1.name.upper()),
+ )
+ constraint.validate(
+ UniqueConstraintProduct,
+ UniqueConstraintProduct(name="another-name"),
+ )
+ # Existing instances have their existing row excluded.
+ constraint.validate(UniqueConstraintProduct, self.p1)
+ # Unique field is excluded.
+ constraint.validate(
+ UniqueConstraintProduct,
+ UniqueConstraintProduct(name=self.p1.name.upper()),
+ exclude={"name"},
+ )
+
def test_validate_expression_condition(self):
constraint = models.UniqueConstraint(
Lower("name"),