[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:
constraint.validate(model_class, self, exclude=exclude, using=using)
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)
else:
errors = e.update_error_dict(errors)

View File

@ -12,4 +12,5 @@ in 4.1.6.
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.db import IntegrityError, connection, models
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.transaction import atomic
from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature
@ -589,6 +589,26 @@ class UniqueConstraintTests(TestCase):
with self.assertRaisesMessage(ValidationError, msg):
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):
constraint = UniqueConstraintProduct._meta.constraints[0]
msg = "Unique constraint product with this Name and Color already exists."