diff options
| author | David Sanders <shang.xiao.sanders@gmail.com> | 2024-08-05 08:22:29 +0200 |
|---|---|---|
| committer | Sarah Boyce <42296566+sarahboyce@users.noreply.github.com> | 2024-08-05 17:36:15 +0200 |
| commit | aed4ffe1897c51c0dfd8689c0834ca4ca0a8a03e (patch) | |
| tree | 409778e06c17bbc9f828db340b431c030e5e400b /tests | |
| parent | 78654a29b851751f347d51dbfe5ba8a996c012ba (diff) | |
[5.1.x] Fixed #35638 -- Updated validate_constraints to consider db_default.
Backport of 509763c79952cde02d9f5b584af4278bdbed77b2 from main.
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/constraints/models.py | 7 | ||||
| -rw-r--r-- | tests/constraints/tests.py | 57 | ||||
| -rw-r--r-- | tests/postgres_tests/migrations/0002_create_test_models.py | 2 | ||||
| -rw-r--r-- | tests/postgres_tests/models.py | 2 | ||||
| -rw-r--r-- | tests/postgres_tests/test_constraints.py | 9 | ||||
| -rw-r--r-- | tests/validation/models.py | 2 | ||||
| -rw-r--r-- | tests/validation/test_unique.py | 14 |
7 files changed, 89 insertions, 4 deletions
diff --git a/tests/constraints/models.py b/tests/constraints/models.py index 87b97b2a85..983d550502 100644 --- a/tests/constraints/models.py +++ b/tests/constraints/models.py @@ -128,3 +128,10 @@ class JSONFieldModel(models.Model): class Meta: required_db_features = {"supports_json_field"} + + +class ModelWithDatabaseDefault(models.Model): + field = models.CharField(max_length=255) + field_with_db_default = models.CharField( + max_length=255, db_default=models.Value("field_with_db_default") + ) diff --git a/tests/constraints/tests.py b/tests/constraints/tests.py index 32f98a5529..f54fb1faee 100644 --- a/tests/constraints/tests.py +++ b/tests/constraints/tests.py @@ -4,7 +4,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, UniqueConstraint -from django.db.models.functions import Abs, Lower +from django.db.models.functions import Abs, Lower, Upper from django.db.transaction import atomic from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature from django.test.utils import ignore_warnings @@ -14,6 +14,7 @@ from .models import ( ChildModel, ChildUniqueConstraintProduct, JSONFieldModel, + ModelWithDatabaseDefault, Product, UniqueConstraintConditionProduct, UniqueConstraintDeferrable, @@ -396,6 +397,33 @@ class CheckConstraintTests(TestCase): with self.assertWarnsRegex(RemovedInDjango60Warning, msg): self.assertIs(constraint.check, other_condition) + def test_database_default(self): + models.CheckConstraint( + condition=models.Q(field_with_db_default="field_with_db_default"), + name="check_field_with_db_default", + ).validate(ModelWithDatabaseDefault, ModelWithDatabaseDefault()) + + # Ensure that a check also does not silently pass with either + # FieldError or DatabaseError when checking with a db_default. + with self.assertRaises(ValidationError): + models.CheckConstraint( + condition=models.Q( + field_with_db_default="field_with_db_default", field="field" + ), + name="check_field_with_db_default_2", + ).validate( + ModelWithDatabaseDefault, ModelWithDatabaseDefault(field="not-field") + ) + + with self.assertRaises(ValidationError): + models.CheckConstraint( + condition=models.Q(field_with_db_default="field_with_db_default"), + name="check_field_with_db_default", + ).validate( + ModelWithDatabaseDefault, + ModelWithDatabaseDefault(field_with_db_default="other value"), + ) + class UniqueConstraintTests(TestCase): @classmethod @@ -1251,3 +1279,30 @@ class UniqueConstraintTests(TestCase): msg = "A unique constraint must be named." with self.assertRaisesMessage(ValueError, msg): models.UniqueConstraint(fields=["field"]) + + def test_database_default(self): + models.UniqueConstraint( + fields=["field_with_db_default"], name="unique_field_with_db_default" + ).validate(ModelWithDatabaseDefault, ModelWithDatabaseDefault()) + models.UniqueConstraint( + Upper("field_with_db_default"), + name="unique_field_with_db_default_expression", + ).validate(ModelWithDatabaseDefault, ModelWithDatabaseDefault()) + + ModelWithDatabaseDefault.objects.create() + + msg = ( + "Model with database default with this Field with db default already " + "exists." + ) + with self.assertRaisesMessage(ValidationError, msg): + models.UniqueConstraint( + fields=["field_with_db_default"], name="unique_field_with_db_default" + ).validate(ModelWithDatabaseDefault, ModelWithDatabaseDefault()) + + msg = "Constraint “unique_field_with_db_default_expression” is violated." + with self.assertRaisesMessage(ValidationError, msg): + models.UniqueConstraint( + Upper("field_with_db_default"), + name="unique_field_with_db_default_expression", + ).validate(ModelWithDatabaseDefault, ModelWithDatabaseDefault()) diff --git a/tests/postgres_tests/migrations/0002_create_test_models.py b/tests/postgres_tests/migrations/0002_create_test_models.py index 5538b436ad..188f79607d 100644 --- a/tests/postgres_tests/migrations/0002_create_test_models.py +++ b/tests/postgres_tests/migrations/0002_create_test_models.py @@ -434,7 +434,7 @@ class Migration(migrations.Migration): primary_key=True, ), ), - ("ints", IntegerRangeField(null=True, blank=True)), + ("ints", IntegerRangeField(null=True, blank=True, db_default=(5, 10))), ("bigints", BigIntegerRangeField(null=True, blank=True)), ("decimals", DecimalRangeField(null=True, blank=True)), ("timestamps", DateTimeRangeField(null=True, blank=True)), diff --git a/tests/postgres_tests/models.py b/tests/postgres_tests/models.py index a97894e327..e3118bc590 100644 --- a/tests/postgres_tests/models.py +++ b/tests/postgres_tests/models.py @@ -130,7 +130,7 @@ class LineSavedSearch(PostgreSQLModel): class RangesModel(PostgreSQLModel): - ints = IntegerRangeField(blank=True, null=True) + ints = IntegerRangeField(blank=True, null=True, db_default=(5, 10)) bigints = BigIntegerRangeField(blank=True, null=True) decimals = DecimalRangeField(blank=True, null=True) timestamps = DateTimeRangeField(blank=True, null=True) diff --git a/tests/postgres_tests/test_constraints.py b/tests/postgres_tests/test_constraints.py index 3cc76cdcfe..9a572c9bf2 100644 --- a/tests/postgres_tests/test_constraints.py +++ b/tests/postgres_tests/test_constraints.py @@ -1238,3 +1238,12 @@ class ExclusionConstraintTests(PostgreSQLTestCase): constraint_name, self.get_constraints(ModelWithExclusionConstraint._meta.db_table), ) + + def test_database_default(self): + constraint = ExclusionConstraint( + name="ints_equal", expressions=[("ints", RangeOperators.EQUAL)] + ) + RangesModel.objects.create() + msg = "Constraint “ints_equal” is violated." + with self.assertRaisesMessage(ValidationError, msg): + constraint.validate(RangesModel, RangesModel()) diff --git a/tests/validation/models.py b/tests/validation/models.py index f6b1e0cd62..beec524758 100644 --- a/tests/validation/models.py +++ b/tests/validation/models.py @@ -48,7 +48,7 @@ class ModelToValidate(models.Model): class UniqueFieldsModel(models.Model): unique_charfield = models.CharField(max_length=100, unique=True) - unique_integerfield = models.IntegerField(unique=True) + unique_integerfield = models.IntegerField(unique=True, db_default=42) non_unique_field = models.IntegerField() diff --git a/tests/validation/test_unique.py b/tests/validation/test_unique.py index 4a8b3894f0..36ee6e9da0 100644 --- a/tests/validation/test_unique.py +++ b/tests/validation/test_unique.py @@ -146,6 +146,20 @@ class PerformUniqueChecksTest(TestCase): mtv = ModelToValidate(number=10, name="Some Name") mtv.full_clean() + def test_unique_db_default(self): + UniqueFieldsModel.objects.create(unique_charfield="foo", non_unique_field=42) + um = UniqueFieldsModel(unique_charfield="bar", non_unique_field=42) + with self.assertRaises(ValidationError) as cm: + um.full_clean() + self.assertEqual( + cm.exception.message_dict, + { + "unique_integerfield": [ + "Unique fields model with this Unique integerfield already exists." + ] + }, + ) + def test_unique_for_date(self): Post.objects.create( title="Django 1.0 is released", |
