使用 django.contrib.gis.measure.D 时 GeoDjango dwithin 错误
Posted
技术标签:
【中文标题】使用 django.contrib.gis.measure.D 时 GeoDjango dwithin 错误【英文标题】:GeoDjango dwithin errors when using django.contrib.gis.measure.D 【发布时间】:2014-08-03 09:17:09 【问题描述】:首先:Python 2.7.6、Django 1.6.5、Postgres 9.3.4、PostGIS 2.1.3、RHEL 6.5 上的 psycopg2 2.5.3
以下是相关模型:
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
这个查询应该可以工作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))
但事实并非如此。第一次调试调用有效,但第二次抛出 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
有谁知道为什么这没有按预期工作?这可能是一个错误,还是我犯了一个我没有看到的错误?
[编辑] 我认为这可能是一个 Django 错误。我继续开票here。一旦我弄清楚正确的解决方法是什么,我会在此处添加答案。
【问题讨论】:
我对geodjango一无所知,但是底层的Postgis函数ST_DWithin的签名是(geometry, geometry, double),尽管我同意你的文档。另外,Postgis 函数接受一个 int 作为第三个参数。 是的,我看到了 ST_DWithin 文档。我假设D
' 的工作是将任何单位转换为 ST_DWithin 期望的双倍(我相信米)。我想我会提交一份 Django 错误报告并在获得更多信息时更新这个问题。
是的,大多数 Postgis 函数都使用仪表,除非您将 SRID 指定为度数,例如 4326。祝您好运。
谢谢!我继续提交了错误报告:code.djangoproject.com/ticket/22830
【参考方案1】:
我收到了对我提交的票证的回复 (https://code.djangoproject.com/ticket/22830)。显然,我发现dwithin
查询与Distance
对象有一个看似未记录(或至少未明确记录)的问题。开发人员这样说:
由于您的对象位于地理坐标中(几何字段默认 到 WGS84),您必须以度数单位提供距离。这是 例如匹配 PostGIS 定义:
boolean ST_DWithin(几何 g1, 几何 g2, 双精度 distance_of_srid);
distance_of_srid 是 WGS84 的度数。所以在你的工作的 5 示例表示 5 度,而不是 5 公里!
看起来他们将澄清文档以使其更清晰(太棒了!)。
由于我想要的是 5km,所以我需要将 5km 转换为度数。 1 度约为 111.325 公里。因此,1km = 1/111.325 度。因此,5 公里约为 0.0449 或约 0.05 度。所以我只需要把我的电话改成这样:
touching_locations = Location.objects.filter(geometry__dwithin=(location.geometry, 0.05))
【讨论】:
如果您改用geography
类型,您可以使用常规长度单位,如 km,但 geometry
使用与 SRID 相同的单位。假设 1km = 1/111.325 度仅适用于赤道附近。
我在第一次定义我的模型时考虑到了这一点,但PostGIS documentation 中的这一行让我失望了:“新的 GEOGRAPHY 类型允许您将数据存储在经度/纬度坐标中,但要付出代价:在 GEOGRAPHY 上定义的函数比在 GEOMETRY 上定义的函数少;那些定义的函数需要更多的 CPU 时间来执行。” postgis.net/docs/manual-2.1/… 表示可用功能有限。
没错,功能较少,但前提是您需要它们。此外,使用 SQL,您始终可以强制转换 geog::geometry
以使用具有笛卡尔假设的几何函数。以上是关于使用 django.contrib.gis.measure.D 时 GeoDjango dwithin 错误的主要内容,如果未能解决你的问题,请参考以下文章
在使用加载数据流步骤的猪中,使用(使用 PigStorage)和不使用它有啥区别?
Qt静态编译时使用OpenSSL有三种方式(不使用,动态使用,静态使用,默认是动态使用)