使用django.contrib.gis.measure.D时GeoDjango dwithin错误

1 投票
1 回答
1456 浏览
提问于 2025-04-18 09:37

首先:使用的是 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 个回答

4

我收到了我提交的工单的回复(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))

撰写回答