mirror of
https://github.com/django/django.git
synced 2025-07-12 07:45:11 +00:00
Refs #33342 -- Removed ExclusionConstraint.opclasses per deprecation timeline.
This commit is contained in:
parent
5c10041f46
commit
23ec318988
5 changed files with 8 additions and 278 deletions
|
@ -16,10 +16,9 @@ from django.db.models import (
|
|||
)
|
||||
from django.db.models.fields.json import KeyTextTransform
|
||||
from django.db.models.functions import Cast, Left, Lower
|
||||
from django.test import ignore_warnings, skipUnlessDBFeature
|
||||
from django.test import skipUnlessDBFeature
|
||||
from django.test.utils import isolate_apps
|
||||
from django.utils import timezone
|
||||
from django.utils.deprecation import RemovedInDjango50Warning
|
||||
|
||||
from . import PostgreSQLTestCase
|
||||
from .models import HotelReservation, IntegerArrayModel, RangesModel, Room, Scene
|
||||
|
@ -328,30 +327,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||
include="invalid",
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_invalid_opclasses_type(self):
|
||||
msg = "ExclusionConstraint.opclasses must be a list or tuple."
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
ExclusionConstraint(
|
||||
name="exclude_invalid_opclasses",
|
||||
expressions=[(F("datespan"), RangeOperators.OVERLAPS)],
|
||||
opclasses="invalid",
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_opclasses_and_expressions_same_length(self):
|
||||
msg = (
|
||||
"ExclusionConstraint.expressions and "
|
||||
"ExclusionConstraint.opclasses must have the same number of "
|
||||
"elements."
|
||||
)
|
||||
with self.assertRaisesMessage(ValueError, msg):
|
||||
ExclusionConstraint(
|
||||
name="exclude_invalid_expressions_opclasses_length",
|
||||
expressions=[(F("datespan"), RangeOperators.OVERLAPS)],
|
||||
opclasses=["foo", "bar"],
|
||||
)
|
||||
|
||||
def test_repr(self):
|
||||
constraint = ExclusionConstraint(
|
||||
name="exclude_overlapping",
|
||||
|
@ -466,27 +441,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||
],
|
||||
include=["cancelled"],
|
||||
)
|
||||
with ignore_warnings(category=RemovedInDjango50Warning):
|
||||
constraint_8 = ExclusionConstraint(
|
||||
name="exclude_overlapping",
|
||||
expressions=[
|
||||
("datespan", RangeOperators.OVERLAPS),
|
||||
("room", RangeOperators.EQUAL),
|
||||
],
|
||||
include=["cancelled"],
|
||||
opclasses=["range_ops", "range_ops"],
|
||||
)
|
||||
constraint_9 = ExclusionConstraint(
|
||||
name="exclude_overlapping",
|
||||
expressions=[
|
||||
("datespan", RangeOperators.OVERLAPS),
|
||||
("room", RangeOperators.EQUAL),
|
||||
],
|
||||
opclasses=["range_ops", "range_ops"],
|
||||
)
|
||||
self.assertNotEqual(constraint_2, constraint_9)
|
||||
self.assertNotEqual(constraint_7, constraint_8)
|
||||
|
||||
constraint_10 = ExclusionConstraint(
|
||||
name="exclude_overlapping",
|
||||
expressions=[
|
||||
|
@ -636,27 +590,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||
},
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_deconstruct_opclasses(self):
|
||||
constraint = ExclusionConstraint(
|
||||
name="exclude_overlapping",
|
||||
expressions=[("datespan", RangeOperators.OVERLAPS)],
|
||||
opclasses=["range_ops"],
|
||||
)
|
||||
path, args, kwargs = constraint.deconstruct()
|
||||
self.assertEqual(
|
||||
path, "django.contrib.postgres.constraints.ExclusionConstraint"
|
||||
)
|
||||
self.assertEqual(args, ())
|
||||
self.assertEqual(
|
||||
kwargs,
|
||||
{
|
||||
"name": "exclude_overlapping",
|
||||
"expressions": [("datespan", RangeOperators.OVERLAPS)],
|
||||
"opclasses": ["range_ops"],
|
||||
},
|
||||
)
|
||||
|
||||
def _test_range_overlaps(self, constraint):
|
||||
# Create exclusion constraint.
|
||||
self.assertNotIn(
|
||||
|
@ -759,23 +692,6 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||
exclude={"datespan", "start", "end", "room"},
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_range_overlaps_custom_opclasses(self):
|
||||
class TsTzRange(Func):
|
||||
function = "TSTZRANGE"
|
||||
output_field = DateTimeRangeField()
|
||||
|
||||
constraint = ExclusionConstraint(
|
||||
name="exclude_overlapping_reservations_custom",
|
||||
expressions=[
|
||||
(TsTzRange("start", "end", RangeBoundary()), RangeOperators.OVERLAPS),
|
||||
("room", RangeOperators.EQUAL),
|
||||
],
|
||||
condition=Q(cancelled=False),
|
||||
opclasses=["range_ops", "gist_int4_ops"],
|
||||
)
|
||||
self._test_range_overlaps(constraint)
|
||||
|
||||
def test_range_overlaps_custom(self):
|
||||
class TsTzRange(Func):
|
||||
function = "TSTZRANGE"
|
||||
|
@ -1203,137 +1119,3 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
|
|||
constraint_name,
|
||||
self.get_constraints(ModelWithExclusionConstraint._meta.db_table),
|
||||
)
|
||||
|
||||
|
||||
class ExclusionConstraintOpclassesDepracationTests(PostgreSQLTestCase):
|
||||
def get_constraints(self, table):
|
||||
"""Get the constraints on the table using a new cursor."""
|
||||
with connection.cursor() as cursor:
|
||||
return connection.introspection.get_constraints(cursor, table)
|
||||
|
||||
def test_warning(self):
|
||||
msg = (
|
||||
"The opclasses argument is deprecated in favor of using "
|
||||
"django.contrib.postgres.indexes.OpClass in "
|
||||
"ExclusionConstraint.expressions."
|
||||
)
|
||||
with self.assertWarnsMessage(RemovedInDjango50Warning, msg):
|
||||
ExclusionConstraint(
|
||||
name="exclude_overlapping",
|
||||
expressions=[(F("datespan"), RangeOperators.ADJACENT_TO)],
|
||||
opclasses=["range_ops"],
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_repr(self):
|
||||
constraint = ExclusionConstraint(
|
||||
name="exclude_overlapping",
|
||||
expressions=[(F("datespan"), RangeOperators.ADJACENT_TO)],
|
||||
opclasses=["range_ops"],
|
||||
)
|
||||
self.assertEqual(
|
||||
repr(constraint),
|
||||
"<ExclusionConstraint: index_type='GIST' expressions=["
|
||||
"(F(datespan), '-|-')] name='exclude_overlapping' "
|
||||
"opclasses=['range_ops']>",
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_range_adjacent_opclasses(self):
|
||||
constraint_name = "ints_adjacent_opclasses"
|
||||
self.assertNotIn(
|
||||
constraint_name, self.get_constraints(RangesModel._meta.db_table)
|
||||
)
|
||||
constraint = ExclusionConstraint(
|
||||
name=constraint_name,
|
||||
expressions=[("ints", RangeOperators.ADJACENT_TO)],
|
||||
opclasses=["range_ops"],
|
||||
)
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_constraint(RangesModel, constraint)
|
||||
constraints = self.get_constraints(RangesModel._meta.db_table)
|
||||
self.assertIn(constraint_name, constraints)
|
||||
with editor.connection.cursor() as cursor:
|
||||
cursor.execute(SchemaTests.get_opclass_query, [constraint.name])
|
||||
self.assertEqual(
|
||||
cursor.fetchall(),
|
||||
[("range_ops", constraint.name)],
|
||||
)
|
||||
RangesModel.objects.create(ints=(20, 50))
|
||||
with self.assertRaises(IntegrityError), transaction.atomic():
|
||||
RangesModel.objects.create(ints=(10, 20))
|
||||
RangesModel.objects.create(ints=(10, 19))
|
||||
RangesModel.objects.create(ints=(51, 60))
|
||||
# Drop the constraint.
|
||||
with connection.schema_editor() as editor:
|
||||
editor.remove_constraint(RangesModel, constraint)
|
||||
self.assertNotIn(
|
||||
constraint_name, self.get_constraints(RangesModel._meta.db_table)
|
||||
)
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_range_adjacent_opclasses_condition(self):
|
||||
constraint_name = "ints_adjacent_opclasses_condition"
|
||||
self.assertNotIn(
|
||||
constraint_name, self.get_constraints(RangesModel._meta.db_table)
|
||||
)
|
||||
constraint = ExclusionConstraint(
|
||||
name=constraint_name,
|
||||
expressions=[("ints", RangeOperators.ADJACENT_TO)],
|
||||
opclasses=["range_ops"],
|
||||
condition=Q(id__gte=100),
|
||||
)
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_constraint(RangesModel, constraint)
|
||||
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_range_adjacent_opclasses_deferrable(self):
|
||||
constraint_name = "ints_adjacent_opclasses_deferrable"
|
||||
self.assertNotIn(
|
||||
constraint_name, self.get_constraints(RangesModel._meta.db_table)
|
||||
)
|
||||
constraint = ExclusionConstraint(
|
||||
name=constraint_name,
|
||||
expressions=[("ints", RangeOperators.ADJACENT_TO)],
|
||||
opclasses=["range_ops"],
|
||||
deferrable=Deferrable.DEFERRED,
|
||||
)
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_constraint(RangesModel, constraint)
|
||||
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
def test_range_adjacent_gist_opclasses_include(self):
|
||||
constraint_name = "ints_adjacent_gist_opclasses_include"
|
||||
self.assertNotIn(
|
||||
constraint_name, self.get_constraints(RangesModel._meta.db_table)
|
||||
)
|
||||
constraint = ExclusionConstraint(
|
||||
name=constraint_name,
|
||||
expressions=[("ints", RangeOperators.ADJACENT_TO)],
|
||||
index_type="gist",
|
||||
opclasses=["range_ops"],
|
||||
include=["decimals"],
|
||||
)
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_constraint(RangesModel, constraint)
|
||||
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango50Warning)
|
||||
@skipUnlessDBFeature("supports_covering_spgist_indexes")
|
||||
def test_range_adjacent_spgist_opclasses_include(self):
|
||||
constraint_name = "ints_adjacent_spgist_opclasses_include"
|
||||
self.assertNotIn(
|
||||
constraint_name, self.get_constraints(RangesModel._meta.db_table)
|
||||
)
|
||||
constraint = ExclusionConstraint(
|
||||
name=constraint_name,
|
||||
expressions=[("ints", RangeOperators.ADJACENT_TO)],
|
||||
index_type="spgist",
|
||||
opclasses=["range_ops"],
|
||||
include=["decimals"],
|
||||
)
|
||||
with connection.schema_editor() as editor:
|
||||
editor.add_constraint(RangesModel, constraint)
|
||||
self.assertIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue