diff options
| author | Simon Charette <charette.s@gmail.com> | 2024-07-13 22:09:50 -0400 |
|---|---|---|
| committer | Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> | 2024-07-17 12:55:36 +0200 |
| commit | a2791f5ea2cb3bfa5b386083002461be40708297 (patch) | |
| tree | 3c38fbaa1cd61d190a6e5d39bb789c65e0e64ded | |
| parent | df7ebb8b0205273f71c60c33a5de0b680d6a3849 (diff) | |
[5.1.x] Refs #30581 -- Made unattached UniqueConstraint(fields) validation testable.
The logic allowing UniqueConstraint(fields).validate to preserve backward
compatiblity with Model.unique_error_message failed to account for cases where
the constraint might not be attached to a model which is a common pattern
during testing.
This changes allows for arbitrary UniqueConstraint(fields) to be tested in
isolation without requiring actual models backing them up.
Co-authored-by: Mark G <mark.gensler@protonmail.com>
Backport of 13922580cccfb9ab2922ff4943dd39da56dfbd8c from main.
| -rw-r--r-- | django/db/models/constraints.py | 19 | ||||
| -rw-r--r-- | tests/constraints/tests.py | 9 |
2 files changed, 16 insertions, 12 deletions
diff --git a/django/db/models/constraints.py b/django/db/models/constraints.py index 3e6c5205c6..9bb407274c 100644 --- a/django/db/models/constraints.py +++ b/django/db/models/constraints.py @@ -653,19 +653,16 @@ class UniqueConstraint(BaseConstraint): queryset = queryset.exclude(pk=model_class_pk) if not self.condition: if queryset.exists(): - if self.expressions: + if self.fields: + # When fields are defined, use the unique_error_message() for + # backward compatibility. raise ValidationError( - self.get_violation_error_message(), - code=self.violation_error_code, + instance.unique_error_message(model, self.fields), ) - # When fields are defined, use the unique_error_message() for - # backward compatibility. - for model, constraints in instance.get_constraints(): - for constraint in constraints: - if constraint is self: - raise ValidationError( - instance.unique_error_message(model, self.fields), - ) + raise ValidationError( + self.get_violation_error_message(), + code=self.violation_error_code, + ) else: against = instance._get_field_value_map(meta=model._meta, exclude=exclude) try: diff --git a/tests/constraints/tests.py b/tests/constraints/tests.py index 86efaa79e7..8b7599adc1 100644 --- a/tests/constraints/tests.py +++ b/tests/constraints/tests.py @@ -896,6 +896,13 @@ class UniqueConstraintTests(TestCase): ChildUniqueConstraintProduct(name=self.p1.name, color=self.p1.color), ) + def test_validate_fields_unattached(self): + Product.objects.create(price=42) + constraint = models.UniqueConstraint(fields=["price"], name="uniq_prices") + msg = "Product with this Price already exists." + with self.assertRaisesMessage(ValidationError, msg): + constraint.validate(Product, Product(price=42)) + @skipUnlessDBFeature("supports_partial_indexes") def test_validate_condition(self): p1 = UniqueConstraintConditionProduct.objects.create(name="p1") @@ -921,7 +928,7 @@ class UniqueConstraintTests(TestCase): ) @skipUnlessDBFeature("supports_partial_indexes") - def test_validate_conditon_custom_error(self): + def test_validate_condition_custom_error(self): p1 = UniqueConstraintConditionProduct.objects.create(name="p1") constraint = models.UniqueConstraint( fields=["name"], |
