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:
parent
92c72b68b7
commit
bb9e82f274
|
@ -36,6 +36,9 @@ class BaseSpatialFeatures:
|
||||||
# The following properties indicate if the database backend support
|
# The following properties indicate if the database backend support
|
||||||
# certain lookups (dwithin, left and right, relate, ...)
|
# certain lookups (dwithin, left and right, relate, ...)
|
||||||
supports_left_right_lookups = False
|
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?
|
# Does the database have raster support?
|
||||||
supports_raster = False
|
supports_raster = False
|
||||||
|
|
|
@ -9,3 +9,4 @@ class DatabaseFeatures(BaseSpatialFeatures, OracleDatabaseFeatures):
|
||||||
supports_geometry_field_introspection = False
|
supports_geometry_field_introspection = False
|
||||||
supports_geometry_field_unique_index = False
|
supports_geometry_field_unique_index = False
|
||||||
supports_perimeter_geodetic = True
|
supports_perimeter_geodetic = True
|
||||||
|
supports_dwithin_distance_expr = False
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django.contrib.gis.db.models.fields import BaseSpatialField
|
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.expressions import Expression
|
||||||
from django.db.models.lookups import Lookup, Transform
|
from django.db.models.lookups import Lookup, Transform
|
||||||
from django.db.models.sql.query import Query
|
from django.db.models.sql.query import Query
|
||||||
|
@ -301,7 +303,20 @@ class DistanceLookupBase(GISLookup):
|
||||||
@BaseSpatialField.register_lookup
|
@BaseSpatialField.register_lookup
|
||||||
class DWithinLookup(DistanceLookupBase):
|
class DWithinLookup(DistanceLookupBase):
|
||||||
lookup_name = 'dwithin'
|
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):
|
def process_rhs(self, compiler, connection):
|
||||||
dist_sql, dist_params = self.process_distance(compiler, connection)
|
dist_sql, dist_params = self.process_distance(compiler, connection)
|
||||||
|
|
|
@ -28,6 +28,7 @@ class AustraliaCity(NamedModel):
|
||||||
"City model for Australia, using WGS84."
|
"City model for Australia, using WGS84."
|
||||||
point = models.PointField()
|
point = models.PointField()
|
||||||
radius = models.IntegerField(default=10000)
|
radius = models.IntegerField(default=10000)
|
||||||
|
allowed_distance = models.FloatField(default=0.5)
|
||||||
|
|
||||||
|
|
||||||
class CensusZipcode(NamedModel):
|
class CensusZipcode(NamedModel):
|
||||||
|
|
|
@ -234,6 +234,30 @@ class DistanceTest(TestCase):
|
||||||
).filter(annotated_value=True)
|
).filter(annotated_value=True)
|
||||||
self.assertEqual(self.get_names(qs), ['77002', '77025', '77401'])
|
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')),
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
=============================
|
=============================
|
||||||
|
|
Loading…
Reference in New Issue