summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Sanders <shang.xiao.sanders@gmail.com>2022-08-09 16:16:23 +1000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-08-09 20:13:21 +0200
commite0ae1363ec2aa71945be26f869cafd4181ccbc95 (patch)
treee76e177099dec1742c46ed4451b75a24b0d3a6ba
parente0ac72fe80a806421dcbbbac22e483b27d2ede7b (diff)
Fixed #33905 -- Fixed CheckConstraint() validation on range fields.
Bug in 667105877e6723c6985399803a364848891513cc.
-rw-r--r--django/contrib/postgres/fields/ranges.py3
-rw-r--r--docs/releases/4.1.1.txt3
-rw-r--r--tests/postgres_tests/test_constraints.py35
3 files changed, 41 insertions, 0 deletions
diff --git a/django/contrib/postgres/fields/ranges.py b/django/contrib/postgres/fields/ranges.py
index f0a2a58936..6230b2f887 100644
--- a/django/contrib/postgres/fields/ranges.py
+++ b/django/contrib/postgres/fields/ranges.py
@@ -78,6 +78,9 @@ class RangeField(models.Field):
def _choices_is_value(cls, value):
return isinstance(value, (list, tuple)) or super()._choices_is_value(value)
+ def get_placeholder(self, value, compiler, connection):
+ return "%s::{}".format(self.db_type(connection))
+
def get_prep_value(self, value):
if value is None:
return None
diff --git a/docs/releases/4.1.1.txt b/docs/releases/4.1.1.txt
index dbac1ff926..55c0b7ed08 100644
--- a/docs/releases/4.1.1.txt
+++ b/docs/releases/4.1.1.txt
@@ -32,3 +32,6 @@ Bugfixes
* Fixed a bug in Django 4.1 that caused a crash of model validation on
``UniqueConstraint()`` with field names in ``expressions`` (:ticket:`33902`).
+
+* Fixed a bug in Django 4.1 that caused an incorrect validation of
+ ``CheckConstraint()`` with range fields on PostgreSQL (:ticket:`33905`).
diff --git a/tests/postgres_tests/test_constraints.py b/tests/postgres_tests/test_constraints.py
index b3822e5805..a6f7b5be85 100644
--- a/tests/postgres_tests/test_constraints.py
+++ b/tests/postgres_tests/test_constraints.py
@@ -123,6 +123,41 @@ class SchemaTests(PostgreSQLTestCase):
timestamps_inner=(datetime_1, datetime_2),
)
+ def test_check_constraint_range_contains(self):
+ constraint = CheckConstraint(
+ check=Q(ints__contains=(1, 5)),
+ name="ints_contains",
+ )
+ msg = f"Constraint “{constraint.name}” is violated."
+ with self.assertRaisesMessage(ValidationError, msg):
+ constraint.validate(RangesModel, RangesModel(ints=(6, 10)))
+
+ def test_check_constraint_range_lower_upper(self):
+ constraint = CheckConstraint(
+ check=Q(ints__startswith__gte=0) & Q(ints__endswith__lte=99),
+ name="ints_range_lower_upper",
+ )
+ msg = f"Constraint “{constraint.name}” is violated."
+ with self.assertRaisesMessage(ValidationError, msg):
+ constraint.validate(RangesModel, RangesModel(ints=(-1, 20)))
+ with self.assertRaisesMessage(ValidationError, msg):
+ constraint.validate(RangesModel, RangesModel(ints=(0, 100)))
+ constraint.validate(RangesModel, RangesModel(ints=(0, 99)))
+
+ def test_check_constraint_range_lower_with_nulls(self):
+ constraint = CheckConstraint(
+ check=Q(ints__isnull=True) | Q(ints__startswith__gte=0),
+ name="ints_optional_positive_range",
+ )
+ constraint.validate(RangesModel, RangesModel())
+ constraint = CheckConstraint(
+ check=Q(ints__startswith__gte=0),
+ name="ints_positive_range",
+ )
+ msg = f"Constraint “{constraint.name}” is violated."
+ with self.assertRaisesMessage(ValidationError, msg):
+ constraint.validate(RangesModel, RangesModel())
+
def test_opclass(self):
constraint = UniqueConstraint(
name="test_opclass",