解决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
相关产品推荐
相关产品推荐

