【问题标题】:Is a GeoDjango MultiPolygonField supposed to accept a Polygon geometry?GeoDjango MultiPolygonField 是否应该接受多边形几何?
【发布时间】:2020-07-21 01:31:32
【问题描述】:

当我尝试在 MultiPolygonField 上设置 Polygon 时,会引发以下异常:

Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/mattrowbum/.virtualenvs/my_env/lib/python3.7/site-packages/django/contrib/gis/db/models/proxy.py", line 75, in __set__
    instance.__class__.__name__, gtype, type(value)))
TypeError: Cannot set Location SpatialProxy (MULTIPOLYGON) with value of type: <class 'django.contrib.gis.geos.polygon.Polygon'>

这是可以理解的,除了GeoDjango tutorial 中的注释指出:

...GeoDjango MultiPolygonField 将接受多边形几何体。

我查看了source of proxy.py,它正在检查值(Polygon)是否是相关几何类(MultiPolygon)的实例。我已经尝试手动进行此检查,以确认 Polygon 不会从 MultiPolygon 继承:

>>> from django.contrib.gis.geos import MultiPolygon, Polygon
>>> ext_coords = ((0, 0), (0, 1), (1, 1), (1, 0), (0, 0))
>>> int_coords = ((0.4, 0.4), (0.4, 0.6), (0.6, 0.6), (0.6, 0.4), (0.4, 0.4))
>>> poly = Polygon(ext_coords, int_coords)
>>> isinstance(poly, Polygon)
True
>>> isinstance(poly, MultiPolygon)
False

我在尝试简化现有存储的MultiPolygon 值时注意到了这一点。下面是我的模型:

from django.contrib.gis.db import models

class Location(models.Model):
    name = models.CharField(max_length=180)
    mpoly = models.MultiPolygonField(geography=True, blank=True, null=True)

我用来简化MultiPolygon 的过程如下。最后一行导致引发异常:

>>> from my_app.models import Location
>>> location = Location.objects.get(pk=1)
>>> geom = location.mpoly
>>> simplified_geom = geom.simplify(0.0002)
>>> location.mpoly = simplified_geom

如果我使用Polygon 创建MultiPolygon,它可以正常工作:

>>> multi = MultiPolygon([simplified_geom,])
>>> location.mpoly = multi

教程中的注释是否具有误导性或我做错了什么?


编辑:对几何形状的进一步测试。

MultiPolygon直接来自模型字段:

>>> geom = Location.mpoly
>>> type(geom)
<class 'django.contrib.gis.geos.collections.MultiPolygon'>
>>> geom.geom_type
'MultiPolygon'
>>> geom.valid
True
>>> geom.srid
4326

应用simplify() 方法:

>>> simplified_geom = geom.simplify(0.0002)
>>> type(simplified_geom)
<class 'django.contrib.gis.geos.polygon.Polygon'>
>>> simplified_geom.geom_type
'Polygon'
>>> simplified_geom.valid
True
>>> simplified_geom.srid
4326

从简化几何创建MultiPolygon

>>> multi = MultiPolygon([simplified_geom,])
>>> type(multi)
<class 'django.contrib.gis.geos.collections.MultiPolygon'>
>>> multi.geom_type
'MultiPolygon'
>>> multi.valid
True
>>> multi.srid
>>> print(multi.srs)
None

请注意,上面的MultiPolygon 没有 SRID。我认为这可能是被接受的原因。我使用srid=4326 参数创建了一个,但它也被该领域接受。

这是一个非常基本的问题示例:

>>> # This works
>>> location.mpoly = MultiPolygon()
>>> # This doesn't
>>> location.mpoly = Polygon()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/mattrowbum/.virtualenvs/musicteacher/lib/python3.7/site-packages/django/contrib/gis/db/models/proxy.py", line 75, in __set__
    instance.__class__.__name__, gtype, type(value)))
TypeError: Cannot set Location SpatialProxy (MULTIPOLYGON) with value of type: <class 'django.contrib.gis.geos.polygon.Polygon'>

【问题讨论】:

  • 您能分享一下Model,更具体地说是MultiPolygonField 的创作吗?你在那里使用geography=True 选项吗?
  • @JohnMoutafis - 我已经用模型声明和流程更新了问题。从那以后,我研究了LayerMapping 实用程序的来源,在这种情况下,如果提供了单个几何图形,它就会构造一个多几何图形。
  • 是的,我以前见过,问题在于geography=True 设置和您在该字段中传递的多边形:stackoverflow.com/questions/55451675/…

标签: django geodjango geos


【解决方案1】:

编辑:

虽然MultiPolygon code 似乎允许将Polygon 存储为MultiPolygon 对象:

class MultiPolygon(GeometryCollection):
    _allowed = Polygon
    _typeid = 6

您提出的问题随着您的描述而上升。

我已经尝试了一些变通方法,唯一令我满意的方法是将您的 geom 字段重构为可以存储任何类型几何图形的通用 GeometryField

另一个不接触模型的选择是将每个Polygon 转换为MultiPolygon,然后再将其插入字段:

p = Polygon()
location.mpoly = MultiPolygon(p)

在我看来,这值得一个教程更新请求或代码修复的问题。


在此处保留之前的答案状态以保持评论的连续性:

The issue is with the geography=True setting 而不是该字段,因为MultiPolygonField 确实接受Polygon 以及MultiPolygon

geography 类型为使用地理坐标(例如 WGS84 经度/纬度)表示的空间特征提供本机支持。 与几何类型使用的平面不同,geography 类型使用其球面表示数据。在地理列上执行的距离和测量操作会自动采用大​​圆弧计算并返回线性单位。换句话说,当在两个地理上调用 ST_Distance 时,会返回一个以米为单位的值(与在 WGS84 中的几何列上调用度数相反)。

由于您将字段设置为期望地理类型对象,因此如果您尝试传递多边形的非地理表示,您将收到相关错误。

【讨论】:

  • 感谢您的回答约翰,但我还是有点困惑。我所做的只是使用simplify 方法从原始字段值创建一个新的GEOSGeometry。创建的 Polygon 的 SRID 仍然是 4326。还有什么我可以检查的可以指示非地理 Polygon 的吗?
  • 我用一个简单的例子更新了这个问题,表明如果我将新的Polygon 转换为MultiPolygon,它会被接受。
  • @MattRowbum 你能检查失败的几何图形是否仍然是 Polygon 并且在 simplify 之后是 valid 吗?
  • 谢谢@JohnMoutafis - 是的,我可以确认它既是Polygon 也是有效的。我在问题的末尾添加了更多测试结果。它甚至会接受一个空白MultiPolygon,但会引发一个带有空白Polygon 的异常。
  • @MattRowbum 我尝试了您的问题,但找不到令人满意的解决方案:/。也许这是 Django 中的一个错误,应该提出一个问题。我更新了解决方法和我的意见。
猜你喜欢
  • 2015-03-07
  • 2012-11-01
  • 2016-09-03
  • 2010-12-03
  • 1970-01-01
  • 2020-02-23
  • 1970-01-01
  • 2018-02-08
  • 2013-11-22
相关资源
最近更新 更多