mirror of
https://github.com/django/django.git
synced 2025-10-25 06:36:07 +00:00
[5.1.x] Fixed #35560 -- Made Model.full_clean() ignore GeneratedFields for constraints.
Accessing generated field values on unsaved models caused a crash when
validating CheckConstraints and UniqueConstraints with expressions.
Backport of 1005c2abd1 from main.
This commit is contained in:
committed by
Sarah Boyce
parent
3b5d04f879
commit
2da007737c
@@ -2,6 +2,7 @@ import uuid
|
||||
from decimal import Decimal
|
||||
|
||||
from django.apps import apps
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import IntegrityError, connection
|
||||
from django.db.models import (
|
||||
CharField,
|
||||
@@ -18,6 +19,8 @@ from django.test.utils import isolate_apps
|
||||
from .models import (
|
||||
Foo,
|
||||
GeneratedModel,
|
||||
GeneratedModelCheckConstraint,
|
||||
GeneratedModelCheckConstraintVirtual,
|
||||
GeneratedModelFieldWithConverters,
|
||||
GeneratedModelNull,
|
||||
GeneratedModelNullVirtual,
|
||||
@@ -25,6 +28,8 @@ from .models import (
|
||||
GeneratedModelOutputFieldDbCollationVirtual,
|
||||
GeneratedModelParams,
|
||||
GeneratedModelParamsVirtual,
|
||||
GeneratedModelUniqueConstraint,
|
||||
GeneratedModelUniqueConstraintVirtual,
|
||||
GeneratedModelVirtual,
|
||||
)
|
||||
|
||||
@@ -186,6 +191,42 @@ class GeneratedFieldTestMixin:
|
||||
m = self._refresh_if_needed(m)
|
||||
self.assertEqual(m.field, 3)
|
||||
|
||||
@skipUnlessDBFeature("supports_table_check_constraints")
|
||||
def test_full_clean_with_check_constraint(self):
|
||||
model_name = self.check_constraint_model._meta.verbose_name.capitalize()
|
||||
|
||||
m = self.check_constraint_model(a=2)
|
||||
m.full_clean()
|
||||
m.save()
|
||||
m = self._refresh_if_needed(m)
|
||||
self.assertEqual(m.a_squared, 4)
|
||||
|
||||
m = self.check_constraint_model(a=-1)
|
||||
with self.assertRaises(ValidationError) as cm:
|
||||
m.full_clean()
|
||||
self.assertEqual(
|
||||
cm.exception.message_dict,
|
||||
{"__all__": [f"Constraint “{model_name} a > 0” is violated."]},
|
||||
)
|
||||
|
||||
@skipUnlessDBFeature("supports_expression_indexes")
|
||||
def test_full_clean_with_unique_constraint_expression(self):
|
||||
model_name = self.unique_constraint_model._meta.verbose_name.capitalize()
|
||||
|
||||
m = self.unique_constraint_model(a=2)
|
||||
m.full_clean()
|
||||
m.save()
|
||||
m = self._refresh_if_needed(m)
|
||||
self.assertEqual(m.a_squared, 4)
|
||||
|
||||
m = self.unique_constraint_model(a=2)
|
||||
with self.assertRaises(ValidationError) as cm:
|
||||
m.full_clean()
|
||||
self.assertEqual(
|
||||
cm.exception.message_dict,
|
||||
{"__all__": [f"Constraint “{model_name} a” is violated."]},
|
||||
)
|
||||
|
||||
def test_create(self):
|
||||
m = self.base_model.objects.create(a=1, b=2)
|
||||
m = self._refresh_if_needed(m)
|
||||
@@ -305,6 +346,8 @@ class GeneratedFieldTestMixin:
|
||||
class StoredGeneratedFieldTests(GeneratedFieldTestMixin, TestCase):
|
||||
base_model = GeneratedModel
|
||||
nullable_model = GeneratedModelNull
|
||||
check_constraint_model = GeneratedModelCheckConstraint
|
||||
unique_constraint_model = GeneratedModelUniqueConstraint
|
||||
output_field_db_collation_model = GeneratedModelOutputFieldDbCollation
|
||||
params_model = GeneratedModelParams
|
||||
|
||||
@@ -318,5 +361,7 @@ class StoredGeneratedFieldTests(GeneratedFieldTestMixin, TestCase):
|
||||
class VirtualGeneratedFieldTests(GeneratedFieldTestMixin, TestCase):
|
||||
base_model = GeneratedModelVirtual
|
||||
nullable_model = GeneratedModelNullVirtual
|
||||
check_constraint_model = GeneratedModelCheckConstraintVirtual
|
||||
unique_constraint_model = GeneratedModelUniqueConstraintVirtual
|
||||
output_field_db_collation_model = GeneratedModelOutputFieldDbCollationVirtual
|
||||
params_model = GeneratedModelParamsVirtual
|
||||
|
||||
Reference in New Issue
Block a user