如何使用 GeoDjango/PostGIS 满足“enforce_srid_coordinate”约束?

Posted

技术标签:

【中文标题】如何使用 GeoDjango/PostGIS 满足“enforce_srid_coordinate”约束?【英文标题】:How do I satisfy "enforce_srid_coordinate" constraint with GeoDjango/PostGIS? 【发布时间】:2012-05-16 04:49:28 【问题描述】:

我正在使用 GeoDjango,并且有一个带有 PointField 的 Django 模型:

class ArchivrItem(models.Model):
    ...
    coordinate = models.PointField(srid=4326)

当我尝试使用纬度和经度插入新的 ArchivrItem 时,我收到此错误:

ERROR:  new row for relation "archivr_archivritem" violates check constraint "enforce_srid_coordinate"

我可以通过尝试这样做来避免 Django 并直接在 postgresql 中得到相同的错误:

INSERT INTO archivr_archivritem (coordinate) VALUES ('POINT(51.520667 -0.094833)');

我可能对 SRID 和点系统太天真和无知了……我错过了什么?谢谢。

更新:我应该添加约束是什么。对表的约束是:

"enforce_dims_coordinate" CHECK (st_ndims(coordinate) = 2)
"enforce_geotype_coordinate" CHECK (geometrytype(coordinate) = 'POINT'::text OR coordinate IS NULL)
"enforce_srid_coordinate" CHECK (st_srid(coordinate) = 4326)

【问题讨论】:

【参考方案1】:

听起来您正在尝试通过这样做来添加新的存档项:

item = ArchivrItem(coordinate='POINT(51.520667 -0.094833)')
item.save()

由于某种我不确定的原因,这没有得到正确的默认 SRID。但是,明确指定它应该可以工作,例如:

from django.contrib.gis.geos import Point
item = ArchivrItem(coordinate=Point(-0.094833, 51.520667, srid=4326))
item.save()

如果要匹配模型定义,我会说 srid 是可选的,但指定它并没有什么坏处,您可以查看是否只需使用对象方式即可修复它。 https://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#creating-and-saving-geographic-models 有更多示例。

[除此之外,请注意 POINT() 是 X 然后 Y,即 lon 然后 lat,而不是 lat/lon。如果使用“SRID=4326;POINT(-0.094833 51.520667)”扩展 WKT,您可以放入 SRID]

【讨论】:

嗯,我现在已经尝试了所有这些,但错误相同:item = ArchivrItem(coordinate=Point(5, 23))item = ArchivrItem(coordinate=GEOSGeometry('SRID=4326;POINT(5 23)'))item = ArchivrItem(coordinate=GEOSGeometry('POINT(5 23)', srid=4326)) 我已经成功地直接在 SQL 中管理它,方法是将其作为值插入:ST_SetSrid(ST_PointFromText('POINT(5 23)'),4326) PointFromText 有一个 SRID 参数,不需要 SetSrid: postgis.org/docs/ST_PointFromText.html 。你能让它输出它试图运行的 SQL(那个页面有一个例子),看看它试图从 Django 做什么? 啊,谢谢。嗯,所以 Django 正在记录这个:INSERT INTO "archivr_archivritem" ("coordinate") VALUES (ST_GeomFromEWKB('\x010100000000000000000014400000000000003740'::bytea)) RETURNING "archivr_archivritem"."id"; args=(<django.contrib.gis.db.backends.postgis.adapter.PostGISAdapter object at 0x111661d10>) 使用 Django 1.2.3、Postgres 8.4,你给的所有三个版本在这里都没有错误,恐怕。我来自 Django 的 INSERT 包含一个包含 SRID 的 EWKB;你的上面没有并且仅相当于'POINT(5 23)'。如果没有更多的代码访问权限,我无法说出 srid 丢失的位置。【参考方案2】:

在一位同事遇到相同问题后,我们似乎已将此问题归结为安装的 GEOS 版本的问题。使用有这个问题的版本,如果 p 是 django.contrib.gis.geos.Point,p.wkb 和 p.ewkb 返回相同的数据 - EWKB 缺少 SRID 信息。由于 Django 使用 EWKB 构造 SQL 以导入 PostGIS,这就是它失败的原因,无论创建的构造如何。

我以前的 cmets 使用的是 Debian 的 3.2.0,它根本没有显示这个问题。 3.2.3 是此处显示此问题的版本。升级到 3.3.6 解决了这个问题(并且还测试了 3.3.3 这很好)。我会在今天晚些时候尝试其他版本,等我有更多时间尝试进一步追踪它。

您可以通过以下方式查看您的 GEOS 版本:

from django.contrib.gis.geos.libgeos import geos_version
geos_version()

【讨论】:

以上是关于如何使用 GeoDjango/PostGIS 满足“enforce_srid_coordinate”约束?的主要内容,如果未能解决你的问题,请参考以下文章

geodjango(postgis)中两个3D点之间的距离

Heoku Postgres 的问题“无法访问文件“$libdir/postgis-2.1”

使用特定分支时如何满足cocoapod外部依赖

如何让派生类使用基实现来满足接口

如何在 C++ 中使用约束满足来实现密码算法

在 C++11 中使用字符串如何满足条件?