问题
First off: Python 2.7.6, Django 1.6.5, Postgres 9.3.4, PostGIS 2.1.3, psycopg2 2.5.3 on RHEL 6.5
Here's the relevant model:
class Location(models.Model):
name = models.CharField(max_length=255)
geometry = models.MultiPolygonField(blank=True, default=None, null=True)
objects = models.GeoManager() # override the default manager with a GeoManager instance
parent = models.ForeignKey('self', blank=True, default=None, null=True)
def __unicode__(self):
return self.name
This query should work according to the docs:
touching_locations = Location.objects.filter(geometry__dwithin=(location.geometry, D(km=5)))
logging.debug(type(touching_locations))
logging.debug(len(touching_locations))
But it doesn't. The first debug call works, but the second throws a ValueError
:
<class 'django.contrib.gis.db.models.query.GeoQuerySet'>
ValueError: Only numeric values of degree units are allowed on geographic DWithin queries.
If I make a small change by changing D(km=5)
to 5
:
touching_locations = Location.objects.filter(geometry__dwithin=(location.geometry, 5))
logging.debug(type(touching_locations))
logging.debug(len(touching_locations))
All of a sudden it works. The output I get is this:
<class 'django.contrib.gis.db.models.query.GeoQuerySet'>
54
Does anyone know why this isn't working as expected? Is this perhaps a bug, or am I making a mistake I just don't see?
[edit]
I think this may be a Django bug. I went ahead and opened a ticket here. Once I figure out what the proper fix is, I'll add the answer here.
回答1:
I got a response to the ticket I submitted (https://code.djangoproject.com/ticket/22830). Apparently, I found a seemingly undocumented (or at least not clearly documented) problem that dwithin
queries have with Distance
objects. A dev says this:
As your objects are in geographic coordinates (geometry fields default to WGS84), you have to provide the distance as degree units. This is for example matching the PostGIS definition:
boolean ST_DWithin(geometry g1, geometry g2, double precision distance_of_srid);
distance_of_srid being degrees for WGS84. So the 5 that works in your example means 5 degrees, not 5 km!
It looks like they're going to clarify the documentation to make this clearer (great!).
Since what I want is 5km, I need to convert 5km to degrees. 1 degree is approximately 111.325km. Therefore, 1km = 1/111.325 degrees. 5km is therefore approximately 0.0449 or about 0.05 degrees. So I just need to change my call to this:
touching_locations = Location.objects.filter(geometry__dwithin=(location.geometry, 0.05))
来源:https://stackoverflow.com/questions/24194710/geodjango-dwithin-errors-when-using-django-contrib-gis-measure-d