使用django.contrib.gis.measure.D时GeoDjango dwithin错误
首先:使用的是 Python 2.7.6、Django 1.6.5、Postgres 9.3.4、PostGIS 2.1.3 和 psycopg2 2.5.3,运行在 RHEL 6.5 系统上。
这是相关的模型:
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
这个查询应该可以正常工作,根据文档来看是这样的:
touching_locations = Location.objects.filter(geometry__dwithin=(location.geometry, D(km=5)))
logging.debug(type(touching_locations))
logging.debug(len(touching_locations))
但是它并没有正常工作。第一次调试调用是成功的,但第二次却抛出了一个 ValueError
错误:
<class 'django.contrib.gis.db.models.query.GeoQuerySet'>
ValueError: Only numeric values of degree units are allowed on geographic DWithin queries.
如果我稍微改动一下,把 D(km=5)
改成 5
:
touching_locations = Location.objects.filter(geometry__dwithin=(location.geometry, 5))
logging.debug(type(touching_locations))
logging.debug(len(touching_locations))
结果突然就能正常工作了。我得到的输出是:
<class 'django.contrib.gis.db.models.query.GeoQuerySet'>
54
有没有人知道为什么这不按预期工作?这可能是个bug,还是我犯了什么错误但自己没发现呢?
[编辑]
我觉得这可能是 Django 的一个bug。我已经去这里提交了一个问题。一旦我找到合适的解决办法,会把答案补充在这里。
1 个回答
我收到了我提交的工单的回复(https://code.djangoproject.com/ticket/22830)。看起来我发现了一个似乎没有文档说明(或者说说明得不够清楚)的问题,这个问题和dwithin
查询以及Distance
对象有关。一位开发者是这么说的:
因为你的对象使用的是地理坐标(几何字段默认使用WGS84),所以你需要把距离以度数为单位提供。比如说,这和PostGIS的定义是匹配的:
boolean ST_DWithin(geometry g1, geometry g2, double precision distance_of_srid);
这里的distance_of_srid对于WGS84来说是以度为单位的。所以在你的例子中,那个5代表的是5度,而不是5公里!
看起来他们会对文档进行澄清,让这个问题更清楚(太好了!)。
因为我想要的是5公里,所以我需要把5公里转换成度数。1度大约等于111.325公里。因此,1公里等于1/111.325度。所以5公里大约是0.0449度,差不多是0.05度。所以我只需要把我的调用改成这个:
touching_locations = Location.objects.filter(geometry__dwithin=(location.geometry, 0.05))