mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #34291 -- Fixed Meta.constraints validation crash on UniqueConstraint with ordered expressions.
Thanks Dan F for the report.
Bug in 667105877e.
			
			
This commit is contained in:
		| @@ -3,7 +3,7 @@ from types import NoneType | ||||
|  | ||||
| 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 | ||||
| @@ -339,10 +339,12 @@ class UniqueConstraint(BaseConstraint): | ||||
|                     meta=model._meta, exclude=exclude | ||||
|                 ).items() | ||||
|             } | ||||
|             expressions = [ | ||||
|                 Exact(expr, expr.replace_expressions(replacements)) | ||||
|                 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_expressions(replacements))) | ||||
|             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: | ||||
|   | ||||
| @@ -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`). | ||||
|   | ||||
| @@ -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"), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user