mirror of
https://github.com/django/django.git
synced 2024-11-21 19:09:18 +01:00
Fixed #35103 -- Used provided error code and message when fields is set without a condition on UniqueConstraint.
This commit is contained in:
parent
1979b1403a
commit
e970bb7ca7
@ -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(),
|
||||
|
@ -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`.
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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",
|
||||
)
|
||||
]
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user