summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDavid Sanders <shang.xiao.sanders@gmail.com>2024-08-05 08:22:29 +0200
committerSarah Boyce <42296566+sarahboyce@users.noreply.github.com>2024-08-05 17:36:15 +0200
commitaed4ffe1897c51c0dfd8689c0834ca4ca0a8a03e (patch)
tree409778e06c17bbc9f828db340b431c030e5e400b /tests
parent78654a29b851751f347d51dbfe5ba8a996c012ba (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.py7
-rw-r--r--tests/constraints/tests.py57
-rw-r--r--tests/postgres_tests/migrations/0002_create_test_models.py2
-rw-r--r--tests/postgres_tests/models.py2
-rw-r--r--tests/postgres_tests/test_constraints.py9
-rw-r--r--tests/validation/models.py2
-rw-r--r--tests/validation/test_unique.py14
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",