mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
[5.1.x] Fixed #35638 -- Updated validate_constraints to consider db_default.
Backport of 509763c799 from main.
This commit is contained in:
committed by
Sarah Boyce
parent
78654a29b8
commit
aed4ffe189
@@ -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")
|
||||
)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)),
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user