diff options
| author | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-01-26 09:31:40 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2023-01-26 09:34:15 +0100 |
| commit | 26b7a25632e7fe0b897bc9b88b5c364a4b6398b6 (patch) | |
| tree | 8ee9e441058e9a3c6218c3b323bc670d98ddc6e5 | |
| parent | bc48c7dfd65dcfabbeb6aa5f0a5627038d2b7351 (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.py | 12 | ||||
| -rw-r--r-- | docs/releases/4.1.6.txt | 3 | ||||
| -rw-r--r-- | tests/constraints/tests.py | 23 |
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"), |
