Skip to content

Commit

Permalink
[4.1.x] Fixed #34319 -- Fixed Model.validate_constraints() crash on V…
Browse files Browse the repository at this point in the history
…alidationError with no code.

Thanks Mateusz Kurowski for the report.

Regression in 6671058.
Backport of 2fd755b from main
  • Loading branch information
felixxm committed Feb 8, 2023
1 parent ae53649 commit 590a92e
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 3 deletions.
5 changes: 4 additions & 1 deletion django/db/models/base.py
Expand Up @@ -1422,7 +1422,10 @@ def validate_constraints(self, exclude=None):
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)
Expand Down
3 changes: 2 additions & 1 deletion docs/releases/4.1.7.txt
Expand Up @@ -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`).
22 changes: 21 additions & 1 deletion tests/constraints/tests.py
Expand Up @@ -3,7 +3,7 @@
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
Expand Down Expand Up @@ -589,6 +589,26 @@ def test_model_validation_with_condition(self):
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."
Expand Down

0 comments on commit 590a92e

Please sign in to comment.