mirror of
https://github.com/django/django.git
synced 2025-07-03 17:29:12 +00:00
gis: Fixed bug where extra parameters were passed into SQL for dwithin
lookups for geodetic fields; now degree values (no Distance
objects) may be used with dwithin
lookups.
git-svn-id: http://code.djangoproject.com/svn/django/branches/gis@7456 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
1731135661
commit
115d4170ae
@ -228,7 +228,7 @@ def get_geo_where_clause(lookup_type, table_prefix, field, value):
|
||||
if lookup_type == 'relate':
|
||||
op = op(value[1])
|
||||
elif lookup_type in DISTANCE_FUNCTIONS and lookup_type != 'dwithin':
|
||||
if field._unit_name == 'degree':
|
||||
if field.geodetic:
|
||||
# Geodetic distances are only availble from Points to PointFields.
|
||||
if field._geom != 'POINT':
|
||||
raise TypeError('PostGIS spherical operations are only valid on PointFields.')
|
||||
|
@ -79,15 +79,22 @@ class GeometryField(SpatialBackend.Field):
|
||||
super(GeometryField, self).__init__(**kwargs) # Calling the parent initializtion function
|
||||
|
||||
### Routines specific to GeometryField ###
|
||||
def get_distance(self, dist):
|
||||
@property
|
||||
def geodetic(self):
|
||||
return self._unit_name in self.geodetic_units
|
||||
|
||||
def get_distance(self, dist, lookup_type):
|
||||
"""
|
||||
Returns a distance number in units of the field. For example, if
|
||||
`D(km=1)` was passed in and the units of the field were in meters,
|
||||
then 1000 would be returned.
|
||||
"""
|
||||
|
||||
postgis = SpatialBackend.name == 'postgis'
|
||||
if isinstance(dist, Distance):
|
||||
if self._unit_name in self.geodetic_units:
|
||||
if self.geodetic:
|
||||
# Won't allow Distance objects w/DWithin lookups on PostGIS.
|
||||
if postgis and lookup_type == 'dwithin':
|
||||
raise TypeError('Only numeric values of degree units are allowed on geographic DWithin queries.')
|
||||
# Spherical distance calculation parameter should be in meters.
|
||||
dist_param = dist.m
|
||||
else:
|
||||
@ -97,7 +104,7 @@ class GeometryField(SpatialBackend.Field):
|
||||
dist_param = dist
|
||||
|
||||
# Sphereical distance query; returning meters.
|
||||
if SpatialBackend.name == 'postgis' and self._unit_name in self.geodetic_units:
|
||||
if postgis and self.geodetic and lookup_type != 'dwithin':
|
||||
return [gqn(self._spheroid), dist_param]
|
||||
else:
|
||||
return [dist_param]
|
||||
@ -170,7 +177,7 @@ class GeometryField(SpatialBackend.Field):
|
||||
if isinstance(value, (tuple, list)):
|
||||
if lookup_type in SpatialBackend.distance_functions:
|
||||
# Getting the distance parameter in the units of the field.
|
||||
where += self.get_distance(value[1])
|
||||
where += self.get_distance(value[1], lookup_type)
|
||||
elif lookup_type in SpatialBackend.limited_where:
|
||||
pass
|
||||
else:
|
||||
|
@ -17,7 +17,9 @@ class DistanceTest(unittest.TestCase):
|
||||
# the coordinate system of the field, EPSG:32140 (Texas South Central
|
||||
# w/units in meters)
|
||||
stx_pnt = GEOSGeometry('POINT (-95.370401017314293 29.704867409475465)', 4326)
|
||||
|
||||
# Another one for Australia
|
||||
au_pnt = GEOSGeometry('POINT (150.791 -34.4919)', 4326)
|
||||
|
||||
def get_cities(self, qs):
|
||||
cities = [c.name for c in qs]
|
||||
cities.sort()
|
||||
@ -43,8 +45,17 @@ class DistanceTest(unittest.TestCase):
|
||||
dists = [7000, D(km=7), D(mi=4.349)]
|
||||
for dist in dists:
|
||||
qs = SouthTexasCity.objects.filter(point__dwithin=(self.stx_pnt, dist))
|
||||
cities = self.get_cities(qs)
|
||||
self.assertEqual(cities, ['Downtown Houston', 'Southside Place'])
|
||||
self.assertEqual(['Downtown Houston', 'Southside Place'], self.get_cities(qs))
|
||||
|
||||
if isinstance(dist, D):
|
||||
# A TypeError should be raised when trying to pass Distance objects
|
||||
# into a DWithin query using a geodetic field.
|
||||
qs = AustraliaCity.objects.filter(point__dwithin=(self.au_pnt, dist))
|
||||
self.assertRaises(TypeError, qs.count)
|
||||
else:
|
||||
# Actually using a distance value of 0.5 degrees.
|
||||
qs = AustraliaCity.objects.filter(point__dwithin=(self.au_pnt, 0.5)).order_by('name')
|
||||
self.assertEqual(['Mittagong', 'Shellharbour', 'Thirroul', 'Wollongong'], self.get_cities(qs))
|
||||
|
||||
def test03_distance_aggregate(self):
|
||||
"Testing the `distance` GeoQuerySet method."
|
||||
|
Loading…
x
Reference in New Issue
Block a user