1
0
mirror of https://github.com/django/django.git synced 2024-12-22 00:55:44 +00:00

Fixed #35103 -- Used provided error code and message when fields is set without a condition on UniqueConstraint.

This commit is contained in:
gabn88 2024-01-11 17:43:52 +01:00 committed by Sarah Boyce
parent 1979b1403a
commit e970bb7ca7
5 changed files with 89 additions and 23 deletions

View File

@ -690,11 +690,19 @@ class UniqueConstraint(BaseConstraint):
queryset = queryset.exclude(pk=model_class_pk)
if not self.condition:
if queryset.exists():
if self.fields:
# When fields are defined, use the unique_error_message() for
# backward compatibility.
if (
self.fields
and self.violation_error_message
== self.default_violation_error_message
):
# When fields are defined, use the unique_error_message() as
# a default for backward compatibility.
validation_error_message = instance.unique_error_message(
model, self.fields
)
raise ValidationError(
instance.unique_error_message(model, self.fields),
validation_error_message,
code=validation_error_message.code,
)
raise ValidationError(
self.get_violation_error_message(),

View File

@ -282,27 +282,47 @@ PostgreSQL 15+.
.. attribute:: UniqueConstraint.violation_error_code
The error code used when ``ValidationError`` is raised during
:ref:`model validation <validating-objects>`. Defaults to ``None``.
The error code used when a ``ValidationError`` is raised during
:ref:`model validation <validating-objects>`.
This code is *not used* for :class:`UniqueConstraint`\s with
:attr:`~UniqueConstraint.fields` and without a
:attr:`~UniqueConstraint.condition`. Such :class:`~UniqueConstraint`\s have the
same error code as constraints defined with :attr:`.Field.unique` or in
:attr:`Meta.unique_together <django.db.models.Options.constraints>`.
Defaults to :attr:`.BaseConstraint.violation_error_code`, when either
:attr:`.UniqueConstraint.condition` is set or :attr:`.UniqueConstraint.fields`
is not set.
If :attr:`.UniqueConstraint.fields` is set without a
:attr:`.UniqueConstraint.condition`, defaults to the :attr:`Meta.unique_together
<django.db.models.Options.unique_together>` error code when there are multiple
fields, and to the :attr:`.Field.unique` error code when there is a single
field.
.. versionchanged:: 5.2
In older versions, the provided
:attr:`.UniqueConstraint.violation_error_code` was not used when
:attr:`.UniqueConstraint.fields` was set without a
:attr:`.UniqueConstraint.condition`.
``violation_error_message``
---------------------------
.. attribute:: UniqueConstraint.violation_error_message
The error message used when ``ValidationError`` is raised during
:ref:`model validation <validating-objects>`. Defaults to
:attr:`.BaseConstraint.violation_error_message`.
The error message used when a ``ValidationError`` is raised during
:ref:`model validation <validating-objects>`.
This message is *not used* for :class:`UniqueConstraint`\s with
:attr:`~UniqueConstraint.fields` and without a
:attr:`~UniqueConstraint.condition`. Such :class:`~UniqueConstraint`\s show the
same message as constraints defined with
:attr:`.Field.unique` or in
:attr:`Meta.unique_together <django.db.models.Options.constraints>`.
Defaults to :attr:`.BaseConstraint.violation_error_message`, when either
:attr:`.UniqueConstraint.condition` is set or :attr:`.UniqueConstraint.fields`
is not set.
If :attr:`.UniqueConstraint.fields` is set without a
:attr:`.UniqueConstraint.condition`, defaults to the :attr:`Meta.unique_together
<django.db.models.Options.unique_together>` error message when there are
multiple fields, and to the :attr:`.Field.unique` error message when there is a
single field.
.. versionchanged:: 5.2
In older versions, the provided
:attr:`.UniqueConstraint.violation_error_message` was not used when
:attr:`.UniqueConstraint.fields` was set without a
:attr:`.UniqueConstraint.condition`.

View File

@ -358,6 +358,11 @@ Miscellaneous
* ``HttpRequest.accepted_types`` is now sorted by the client's preference, based
on the request's ``Accept`` header.
* :attr:`.UniqueConstraint.violation_error_code` and
:attr:`.UniqueConstraint.violation_error_message` are now always used when
provided. Previously, these were ignored when :attr:`.UniqueConstraint.fields`
were set without a :attr:`.UniqueConstraint.condition`.
* The :func:`~django.template.context_processors.debug` context processor is no
longer included in the default project template.

View File

@ -72,15 +72,13 @@ class GeneratedFieldVirtualProduct(models.Model):
class UniqueConstraintProduct(models.Model):
name = models.CharField(max_length=255)
color = models.CharField(max_length=32, null=True)
age = models.IntegerField(null=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=["name", "color"],
name="name_color_uniq",
# Custom message and error code are ignored.
violation_error_code="custom_code",
violation_error_message="Custom message",
)
]

View File

@ -953,6 +953,41 @@ class UniqueConstraintTests(TestCase):
ChildUniqueConstraintProduct(name=self.p1.name, color=self.p1.color),
)
def test_validate_unique_custom_code_and_message(self):
product = UniqueConstraintProduct.objects.create(
name="test", color="red", age=42
)
code = "custom_code"
message = "Custom message"
multiple_fields_constraint = models.UniqueConstraint(
fields=["color", "age"],
name="color_age_uniq",
violation_error_code=code,
violation_error_message=message,
)
single_field_constraint = models.UniqueConstraint(
fields=["color"],
name="color_uniq",
violation_error_code=code,
violation_error_message=message,
)
with self.assertRaisesMessage(ValidationError, message) as cm:
multiple_fields_constraint.validate(
UniqueConstraintProduct,
UniqueConstraintProduct(
name="new-test", color=product.color, age=product.age
),
)
self.assertEqual(cm.exception.code, code)
with self.assertRaisesMessage(ValidationError, message) as cm:
single_field_constraint.validate(
UniqueConstraintProduct,
UniqueConstraintProduct(name="new-test", color=product.color),
)
self.assertEqual(cm.exception.code, code)
@skipUnlessDBFeature("supports_table_check_constraints")
def test_validate_fields_unattached(self):
Product.objects.create(price=42)