[4.2.x] Fixed #34319 -- Fixed Model.validate_constraints() crash on ValidationError with no code.

Thanks Mateusz Kurowski for the report.

Regression in 667105877e.
Backport of 2fd755b361 from main
This commit is contained in:
Mariusz Felisiak 2023-02-08 16:38:55 +01:00
parent 1f193f7f56
commit 836ae73a89
3 changed files with 27 additions and 3 deletions

View File

@ -1444,7 +1444,10 @@ class Model(AltersData, metaclass=ModelBase):
try: try:
constraint.validate(model_class, self, exclude=exclude, using=using) constraint.validate(model_class, self, exclude=exclude, using=using)
except ValidationError as e: except ValidationError as e:
if e.code == "unique" and len(constraint.fields) == 1: if (
getattr(e, "code", None) == "unique"
and len(constraint.fields) == 1
):
errors.setdefault(constraint.fields[0], []).append(e) errors.setdefault(constraint.fields[0], []).append(e)
else: else:
errors = e.update_error_dict(errors) errors = e.update_error_dict(errors)

View File

@ -12,4 +12,5 @@ in 4.1.6.
Bugfixes Bugfixes
======== ========
* ... * Fixed a bug in Django 4.1 that caused a crash of model validation on
``ValidationError`` with no ``code`` (:ticket:`34319`).

View File

@ -3,7 +3,7 @@ from unittest import mock
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import IntegrityError, connection, models from django.db import IntegrityError, connection, models
from django.db.models import F from django.db.models import F
from django.db.models.constraints import BaseConstraint from django.db.models.constraints import BaseConstraint, UniqueConstraint
from django.db.models.functions import Lower from django.db.models.functions import Lower
from django.db.transaction import atomic from django.db.transaction import atomic
from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature
@ -589,6 +589,26 @@ class UniqueConstraintTests(TestCase):
with self.assertRaisesMessage(ValidationError, msg): with self.assertRaisesMessage(ValidationError, msg):
UniqueConstraintConditionProduct(name=obj2.name).validate_constraints() UniqueConstraintConditionProduct(name=obj2.name).validate_constraints()
def test_model_validation_constraint_no_code_error(self):
class ValidateNoCodeErrorConstraint(UniqueConstraint):
def validate(self, model, instance, **kwargs):
raise ValidationError({"name": ValidationError("Already exists.")})
class NoCodeErrorConstraintModel(models.Model):
name = models.CharField(max_length=255)
class Meta:
constraints = [
ValidateNoCodeErrorConstraint(
Lower("name"),
name="custom_validate_no_code_error",
)
]
msg = "{'name': ['Already exists.']}"
with self.assertRaisesMessage(ValidationError, msg):
NoCodeErrorConstraintModel(name="test").validate_constraints()
def test_validate(self): def test_validate(self):
constraint = UniqueConstraintProduct._meta.constraints[0] constraint = UniqueConstraintProduct._meta.constraints[0]
msg = "Unique constraint product with this Name and Color already exists." msg = "Unique constraint product with this Name and Color already exists."