1
0
mirror of https://github.com/django/django.git synced 2025-10-28 08:06:09 +00:00

[5.0.x] Fixed #35638 -- Updated validate_constraints to consider db_default.

Backport of 509763c799 from main.
This commit is contained in:
David Sanders
2024-08-05 08:22:29 +02:00
committed by Sarah Boyce
parent e88ef6a27d
commit 333cfab512
10 changed files with 144 additions and 13 deletions

View File

@@ -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,
@@ -365,6 +366,47 @@ class CheckConstraintTests(TestCase):
constraint_with_pk.validate(ChildModel, ChildModel(id=1, age=1))
constraint_with_pk.validate(ChildModel, ChildModel(pk=1, age=1), exclude={"pk"})
@skipUnlessDBFeature("supports_json_field")
def test_validate_jsonfield_exact(self):
data = {"release": "5.0.2", "version": "stable"}
json_exact_constraint = models.CheckConstraint(
check=models.Q(data__version="stable"),
name="only_stable_version",
)
json_exact_constraint.validate(JSONFieldModel, JSONFieldModel(data=data))
data = {"release": "5.0.2", "version": "not stable"}
msg = f"Constraint “{json_exact_constraint.name}” is violated."
with self.assertRaisesMessage(ValidationError, msg):
json_exact_constraint.validate(JSONFieldModel, JSONFieldModel(data=data))
def test_database_default(self):
models.CheckConstraint(
check=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(
check=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(
check=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
@@ -1220,3 +1262,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())