summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2023-02-08 16:38:55 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2023-02-08 16:40:38 +0100
commit590a92e4562c8ebd3eb25dc1e878bd1e3eb758d4 (patch)
tree5e9d84fbfe3ae1437f24fdf0ad7afa9087ca80e2
parentae53649b38e103e2f3297da2292f136694feddd8 (diff)
[4.1.x] Fixed #34319 -- Fixed Model.validate_constraints() crash on ValidationError with no code.
Thanks Mateusz Kurowski for the report. Regression in 667105877e6723c6985399803a364848891513cc. Backport of 2fd755b361d3da2cd0440fc9839feb2bb69b027b from main
-rw-r--r--django/db/models/base.py5
-rw-r--r--docs/releases/4.1.7.txt3
-rw-r--r--tests/constraints/tests.py22
3 files changed, 27 insertions, 3 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 38e25f2607..5ecb326af9 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -1422,7 +1422,10 @@ class Model(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)
diff --git a/docs/releases/4.1.7.txt b/docs/releases/4.1.7.txt
index 0a21d39bbd..e74d43c0e5 100644
--- a/docs/releases/4.1.7.txt
+++ b/docs/releases/4.1.7.txt
@@ -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`).
diff --git a/tests/constraints/tests.py b/tests/constraints/tests.py
index 223b4b3cd5..e52d15233c 100644
--- a/tests/constraints/tests.py
+++ b/tests/constraints/tests.py
@@ -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."