You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

解决Django Rest Framework TypeError:无法用字典设置GeoPoint SpatialProxy

问题:上传地理点接口报TypeError错误

环境版本

  • Django==3.2.16
  • djangorestframework==3.12.0
  • djangorestframework-gis==1.0

代码实现

Model定义

from django.contrib.gis.db import models
from django.utils.translation import gettext_lazy as _
class GeoPoint(models.Model):

    POINT_TYPE_CHOICES = (
       ("limite_cusaf","Límite CUSAF"),
       ("limite_cusaf_di","Límite CUSAF y DI"),
       ("limite_2_di","Límite 2 DI"),
       ("limite_3_di_mas","Límite 3 DI o más"),
       ("otros","Otros"),
    )

    geom = models.PointField(verbose_name=_("Localización"), srid=4326)
    id_cusaf = models.CharField(_("ID CUSAF"), max_length=50)
    code = models.CharField(_("Código Punto"), max_length=50)
    point_type = models.CharField(_("Tipo de Punto"), max_length=50, choices=POINT_TYPE_CHOICES)
    observations = models.TextField(_("Observaciones"), null=True, blank=True)
    
    def __str__(self):
        return self.cod_punto  # 注意:字段名应为code,此处存在笔误

    class Meta:
        db_table = 'aggregate_geopunto'
        managed = True
        verbose_name = 'Punto'
        verbose_name_plural = 'Puntos'

Serializer定义

from rest_framework_gis.serializers import GeoFeatureModelSerializer

class GeoPointSerializer(GeoFeatureModelSerializer):

    class Meta:
        model = GeoPoint
        geo_field = "geom"
        fields = ('id','geom','id_cusaf','code',
        'point_type','observations',)
        read_only_fields = ['id',]

View定义

class GeoPointAPICreate(generics.CreateAPIView):
    authentication_classes = []
    permission_classes = ()
    queryset = GeoPoint.objects.all()
    serializer_class = GeoPointSerializer

Postman请求内容

{
    "type": "Feature",
    "geometry": {
        "type": "Point",
        "coordinates": [
            -69.929352,
            18.547504
        ]
    },
    "properties": {
        "id_cusaf": "x001",
        "code": "1",
        "point_type": "limite_cusaf",
        "observations": "observationssdsd"
    }
}

错误栈

Traceback (most recent call last):
  File "/home/ernesto/Programming/django/virtualenvs/fichacusaf/lib/python3.10/site-packages/rest_framework/serializers.py", line 939, in create
    instance = ModelClass._default_manager.create(**validated_data)
  File "/home/ernesto/Programming/django/virtualenvs/fichacusaf/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/ernesto/Programming/django/virtualenvs/fichacusaf/lib/python3.10/site-packages/django/db/models/query.py", line 451, in create
    obj = self.model(**kwargs)
  File "/home/ernesto/Programming/django/virtualenvs/fichacusaf/lib/python3.10/site-packages/django/db/models/base.py", line 488, in __init__
    _setattr(self, field.attname, val)
  File "/home/ernesto/Programming/django/virtualenvs/fichacusaf/lib/python3.10/site-packages/django/contrib/gis/db/models/proxy.py", line 74, in __set__
    raise TypeError('Cannot set %s SpatialProxy (%s) with value of type: %s' % (
TypeError: Cannot set GeoPoint SpatialProxy (POINT) with value of type: <class 'dict'>

解决方案

原因分析

错误核心是:序列化后的validated_data中,geom字段仍为字典格式,而Django的PointField需要接收GEOSGeometry对象,无法直接解析字典,因此抛出类型错误。结合使用的版本,djangorestframework-gis==1.0在处理GeoFeatureModelSerializer的POST请求时,可能未正确将GeoJSON格式的geometry转换为GEOSGeometry对象。

修复步骤

1. 配置正确的请求头

在Postman中,将请求的Content-Type设置为application/geo+json,这是GeoJSON数据的标准MIME类型,确保Serializer能正确识别并解析请求体。

2. 重写Serializer的create方法,手动转换geometry字段

如果步骤1无法解决问题,在Serializer中手动将GeoJSON字典转换为GEOSGeometry对象:

from django.contrib.gis.geos import GEOSGeometry
from rest_framework_gis.serializers import GeoFeatureModelSerializer

class GeoPointSerializer(GeoFeatureModelSerializer):
    class Meta:
        model = GeoPoint
        geo_field = "geom"
        fields = ('id','geom','id_cusaf','code','point_type','observations',)
        read_only_fields = ['id',]

    def create(self, validated_data):
        # 取出geom的字典数据
        geom_dict = validated_data.pop('geom')
        # 将GeoJSON字典转换为GEOSGeometry对象
        geom = GEOSGeometry(f"{geom_dict['type']}({geom_dict['coordinates'][0]} {geom_dict['coordinates'][1]})")
        validated_data['geom'] = geom
        # 调用父类方法创建实例
        return super().create(validated_data)

3. 修复Model中的笔误

Model的__str__方法中引用了不存在的cod_punto字段,应改为实际存在的code字段,避免后续出现其他错误:

def __str__(self):
    return self.code

内容的提问来源于stack exchange,提问作者Ernesto Ruiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 17:30:43