mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #29955 -- Added support for distance expression to the dwithin lookup.
This was missed when adding support to other distance lookups in refs #25499. Thanks Peter Bex for the report and Mariusz for testcases.
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							92c72b68b7
						
					
				
				
					commit
					bb9e82f274
				
			| @@ -36,6 +36,9 @@ class BaseSpatialFeatures: | ||||
|     # The following properties indicate if the database backend support | ||||
|     # certain lookups (dwithin, left and right, relate, ...) | ||||
|     supports_left_right_lookups = False | ||||
|     # Does the backend support expressions for specifying distance in the | ||||
|     # dwithin lookup? | ||||
|     supports_dwithin_distance_expr = True | ||||
|  | ||||
|     # Does the database have raster support? | ||||
|     supports_raster = False | ||||
|   | ||||
| @@ -9,3 +9,4 @@ class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures): | ||||
|     supports_geometry_field_introspection = False | ||||
|     supports_geometry_field_unique_index = False | ||||
|     supports_perimeter_geodetic = True | ||||
|     supports_dwithin_distance_expr = False | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| import re | ||||
|  | ||||
| from django.contrib.gis.db.models.fields import BaseSpatialField | ||||
| from django.contrib.gis.measure import Distance | ||||
| from django.db import NotSupportedError | ||||
| from django.db.models.expressions import Expression | ||||
| from django.db.models.lookups import Lookup, Transform | ||||
| from django.db.models.sql.query import Query | ||||
| @@ -301,7 +303,20 @@ class DistanceLookupBase(GISLookup): | ||||
| @BaseSpatialField.register_lookup | ||||
| class DWithinLookup(DistanceLookupBase): | ||||
|     lookup_name = 'dwithin' | ||||
|     sql_template = '%(func)s(%(lhs)s, %(rhs)s, %%s)' | ||||
|     sql_template = '%(func)s(%(lhs)s, %(rhs)s, %(value)s)' | ||||
|  | ||||
|     def process_distance(self, compiler, connection): | ||||
|         dist_param = self.rhs_params[0] | ||||
|         if ( | ||||
|             not connection.features.supports_dwithin_distance_expr and | ||||
|             hasattr(dist_param, 'resolve_expression') and | ||||
|             not isinstance(dist_param, Distance) | ||||
|         ): | ||||
|             raise NotSupportedError( | ||||
|                 'This backend does not support expressions for specifying ' | ||||
|                 'distance in the dwithin lookup.' | ||||
|             ) | ||||
|         return super().process_distance(compiler, connection) | ||||
|  | ||||
|     def process_rhs(self, compiler, connection): | ||||
|         dist_sql, dist_params = self.process_distance(compiler, connection) | ||||
|   | ||||
| @@ -28,6 +28,7 @@ class AustraliaCity(NamedModel): | ||||
|     "City model for Australia, using WGS84." | ||||
|     point = models.PointField() | ||||
|     radius = models.IntegerField(default=10000) | ||||
|     allowed_distance = models.FloatField(default=0.5) | ||||
|  | ||||
|  | ||||
| class CensusZipcode(NamedModel): | ||||
|   | ||||
| @@ -234,6 +234,30 @@ class DistanceTest(TestCase): | ||||
|         ).filter(annotated_value=True) | ||||
|         self.assertEqual(self.get_names(qs), ['77002', '77025', '77401']) | ||||
|  | ||||
|     @skipUnlessDBFeature('supports_dwithin_lookup', 'supports_dwithin_distance_expr') | ||||
|     def test_dwithin_with_expression_rhs(self): | ||||
|         # LineString of Wollongong and Adelaide coords. | ||||
|         ls = LineString(((150.902, -34.4245), (138.6, -34.9258)), srid=4326) | ||||
|         qs = AustraliaCity.objects.filter( | ||||
|             point__dwithin=(ls, F('allowed_distance')), | ||||
|         ).order_by('name') | ||||
|         self.assertEqual( | ||||
|             self.get_names(qs), | ||||
|             ['Adelaide', 'Mittagong', 'Shellharbour', 'Thirroul', 'Wollongong'], | ||||
|         ) | ||||
|  | ||||
|     @skipIfDBFeature('supports_dwithin_distance_expr') | ||||
|     def test_dwithin_with_expression_rhs_not_supported(self): | ||||
|         ls = LineString(((150.902, -34.4245), (138.6, -34.9258)), srid=4326) | ||||
|         msg = ( | ||||
|             'This backend does not support expressions for specifying ' | ||||
|             'distance in the dwithin lookup.' | ||||
|         ) | ||||
|         with self.assertRaisesMessage(NotSupportedError, msg): | ||||
|             list(AustraliaCity.objects.filter( | ||||
|                 point__dwithin=(ls, F('allowed_distance')), | ||||
|             )) | ||||
|  | ||||
|  | ||||
| ''' | ||||
| ============================= | ||||
|   | ||||
		Reference in New Issue
	
	Block a user