GeoDjango MultiPolygonField 是否应该接受多边形几何体?

问题描述 投票:0回答:2

当我尝试在

Polygon
上设置
MultiPolygonField
时,会引发以下异常:

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 教程中的注释指出:

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

我查看了 proxy.py 源代码,它正在检查该值(a

Polygon
)是否是相关几何类(a
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'>
django geodjango geos
2个回答
3
投票

编辑:

虽然

MultiPolygon
代码 似乎允许将
Polygon
存储为
MultiPolygon
对象:

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

您所提出的问题随着您的描述而出现。

我尝试了一些解决方法,唯一让我有点满意的方法是将您的

geom
字段重构为可以存储任何类型几何图形的通用
GeometryField

无需接触模型的另一个选项是将每个

Polygon
转换为
MultiPolygon
,然后再将其插入字段:

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

在我看来,这值得通过教程更新请求或代码修复来解决。


为了评论的连续性,保留之前的答案状态:

问题在于

geography=True
设置,而不是字段,因为
MultiPolygonField
确实接受
Polygon
以及
MultiPolygon
:

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

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


0
投票

和其他人一样,我不得不面对 django geos 提出的这个反复出现的错误:

django Geometry type (Polygon) does not match column type (MultiPolygon)

我在网上看到了几个答案,但没有一个能满足我的要求。最简单,也可能是最直接的方法是在更新数据库之前将多边形“重新转换”为多边形,如下所示:

                this_geom = GEOSGeometry(wkt_w.write(my_multipolygon_which_is_a_polygon))
                # detect if it is a polygon
                if this_geom and isinstance(this_geom, Polygon):
                    # if yes, then cast it into a multipolygon
                    this_geom = MultiPolygon(this_geom)

                my_map, created = my_obj.objects.update_or_create(

                    ...

                defaults={
                    'map': this_geom
                    }
                )
© www.soinside.com 2019 - 2024. All rights reserved.