mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #29916 -- Added lower_inc, lower_inf, upper_inc, and upper_inf lookups for RangeFields.
Co-Authored-By: Mariusz Felisiak <felisiak.mariusz@gmail.com>
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							efc3e32d6d
						
					
				
				
					commit
					24b9f50823
				
			| @@ -284,3 +284,31 @@ class IsEmpty(models.Transform): | ||||
|     lookup_name = 'isempty' | ||||
|     function = 'isempty' | ||||
|     output_field = models.BooleanField() | ||||
|  | ||||
|  | ||||
| @RangeField.register_lookup | ||||
| class LowerInclusive(models.Transform): | ||||
|     lookup_name = 'lower_inc' | ||||
|     function = 'LOWER_INC' | ||||
|     output_field = models.BooleanField() | ||||
|  | ||||
|  | ||||
| @RangeField.register_lookup | ||||
| class LowerInfinite(models.Transform): | ||||
|     lookup_name = 'lower_inf' | ||||
|     function = 'LOWER_INF' | ||||
|     output_field = models.BooleanField() | ||||
|  | ||||
|  | ||||
| @RangeField.register_lookup | ||||
| class UpperInclusive(models.Transform): | ||||
|     lookup_name = 'upper_inc' | ||||
|     function = 'UPPER_INC' | ||||
|     output_field = models.BooleanField() | ||||
|  | ||||
|  | ||||
| @RangeField.register_lookup | ||||
| class UpperInfinite(models.Transform): | ||||
|     lookup_name = 'upper_inf' | ||||
|     function = 'UPPER_INF' | ||||
|     output_field = models.BooleanField() | ||||
|   | ||||
| @@ -864,6 +864,62 @@ Returned objects are empty ranges. Can be chained to valid lookups for a | ||||
|     >>> Event.objects.filter(ages__isempty=True) | ||||
|     <QuerySet []> | ||||
|  | ||||
| .. fieldlookup:: rangefield.lower_inc | ||||
|  | ||||
| ``lower_inc`` | ||||
| ^^^^^^^^^^^^^ | ||||
|  | ||||
| .. versionadded:: 3.1 | ||||
|  | ||||
| Returns objects that have inclusive or exclusive lower bounds, depending on the | ||||
| boolean value passed. Can be chained to valid lookups for a | ||||
| :class:`~django.db.models.BooleanField`. | ||||
|  | ||||
|     >>> Event.objects.filter(ages__lower_inc=True) | ||||
|     <QuerySet [<Event: Soft play>, <Event: Pub trip>]> | ||||
|  | ||||
| .. fieldlookup:: rangefield.lower_inf | ||||
|  | ||||
| ``lower_inf`` | ||||
| ^^^^^^^^^^^^^ | ||||
|  | ||||
| .. versionadded:: 3.1 | ||||
|  | ||||
| Returns objects that have unbounded (infinite) or bounded lower bound, | ||||
| depending on the boolean value passed. Can be chained to valid lookups for a | ||||
| :class:`~django.db.models.BooleanField`. | ||||
|  | ||||
|     >>> Event.objects.filter(ages__lower_inf=True) | ||||
|     <QuerySet []> | ||||
|  | ||||
| .. fieldlookup:: rangefield.upper_inc | ||||
|  | ||||
| ``upper_inc`` | ||||
| ^^^^^^^^^^^^^ | ||||
|  | ||||
| .. versionadded:: 3.1 | ||||
|  | ||||
| Returns objects that have inclusive or exclusive upper bounds, depending on the | ||||
| boolean value passed. Can be chained to valid lookups for a | ||||
| :class:`~django.db.models.BooleanField`. | ||||
|  | ||||
|     >>> Event.objects.filter(ages__upper_inc=True) | ||||
|     <QuerySet []> | ||||
|  | ||||
| .. fieldlookup:: rangefield.upper_inf | ||||
|  | ||||
| ``upper_inf`` | ||||
| ^^^^^^^^^^^^^ | ||||
|  | ||||
| .. versionadded:: 3.1 | ||||
|  | ||||
| Returns objects that have unbounded (infinite) or bounded upper bound, | ||||
| depending on the boolean value passed. Can be chained to valid lookups for a | ||||
| :class:`~django.db.models.BooleanField`. | ||||
|  | ||||
|     >>> Event.objects.filter(ages__upper_inf=True) | ||||
|     <QuerySet [<Event: Pub trip>]> | ||||
|  | ||||
| Defining your own range types | ||||
| ----------------------------- | ||||
|  | ||||
|   | ||||
| @@ -80,6 +80,10 @@ Minor features | ||||
|   :class:`~django.contrib.postgres.fields.ArrayField` and | ||||
|   :class:`~django.contrib.postgres.fields.RangeField`. | ||||
|  | ||||
| * The new :lookup:`rangefield.lower_inc`, :lookup:`rangefield.lower_inf`, | ||||
|   :lookup:`rangefield.upper_inc`, and :lookup:`rangefield.upper_inf` allows | ||||
|   querying :class:`~django.contrib.postgres.fields.RangeField` by a bound type. | ||||
|  | ||||
| :mod:`django.contrib.redirects` | ||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|  | ||||
|   | ||||
| @@ -296,6 +296,30 @@ class TestQuerying(PostgreSQLTestCase): | ||||
|             [self.objs[0], self.objs[1]], | ||||
|         ) | ||||
|  | ||||
|     def test_bound_type(self): | ||||
|         decimals = RangesModel.objects.bulk_create([ | ||||
|             RangesModel(decimals=NumericRange(None, 10)), | ||||
|             RangesModel(decimals=NumericRange(10, None)), | ||||
|             RangesModel(decimals=NumericRange(5, 15)), | ||||
|             RangesModel(decimals=NumericRange(5, 15, '(]')), | ||||
|         ]) | ||||
|         tests = [ | ||||
|             ('lower_inc', True, [decimals[1], decimals[2]]), | ||||
|             ('lower_inc', False, [decimals[0], decimals[3]]), | ||||
|             ('lower_inf', True, [decimals[0]]), | ||||
|             ('lower_inf', False, [decimals[1], decimals[2], decimals[3]]), | ||||
|             ('upper_inc', True, [decimals[3]]), | ||||
|             ('upper_inc', False, [decimals[0], decimals[1], decimals[2]]), | ||||
|             ('upper_inf', True, [decimals[1]]), | ||||
|             ('upper_inf', False, [decimals[0], decimals[2], decimals[3]]), | ||||
|         ] | ||||
|         for lookup, filter_arg, excepted_result in tests: | ||||
|             with self.subTest(lookup=lookup, filter_arg=filter_arg): | ||||
|                 self.assertSequenceEqual( | ||||
|                     RangesModel.objects.filter(**{'decimals__%s' % lookup: filter_arg}), | ||||
|                     excepted_result, | ||||
|                 ) | ||||
|  | ||||
|  | ||||
| class TestQueryingWithRanges(PostgreSQLTestCase): | ||||
|     def test_date_range(self): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user