|
@@ -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
|