mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Refs #33342 -- Removed ExclusionConstraint.opclasses per deprecation timeline.
This commit is contained in:
		| @@ -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)) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user