使用 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有三种方式(不使用,动态使用,静态使用,默认是动态使用)

MySQL db 在按日期排序时使用“使用位置;使用临时;使用文件排序”

使用“使用严格”作为“使用强”的备份

Kettle java脚本组件的使用说明(简单使用升级使用)