TypeError: Cannot set GeoPoint SpatialProxy (POINT) with value of type: <class 'dict'>
I am working with Django, Django Rest Framework, Django Rest Framework GIS and POSTgis database to create an endpoint that should upload a geografical point and all its related information. I have defined a Model, Serializer and View for that purpose. But when making a request using postman I am getting the following error:
TypeError: Cannot set GeoPoint SpatialProxy (POINT) with value of type: <class 'dict'>
I am currently working with:
-
Django==3.2.16 -
djangorestframework==3.12.0 -
djangorestframework-gis==1.0
Model definition:
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
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
This is the image of the POSTman request:
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
-69.929352,
18.547504
]
},
"properties": {
"id_cusaf": "x001",
"code": "1",
"point_type": "limite_cusaf",
"observations": "observationssdsd"
}
}
And this is the complete error:
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'>
I got the same issue with : django==4.2, djangorestframework==3.14.0 and djangorestframework-gis==1.0.
Note : those versions are not officially supported.
A quick solution is to redefine a new serializer class that correctly instantiate a GEOSGeometry.
Here is such a class :
class InstantiatingGeoFeatureModelSerializer(GeoFeatureModelSerializer):
def to_internal_value(self, data):
result = super().to_internal_value(data)
result[self.Meta.geo_field] = GEOSGeometry(
json.dumps(result[self.Meta.geo_field])
)
return result
A quick solution is to redefine a new serializer class that correctly instantiate a GEOSGeometry.
Here is such a class :
class InstantiatingGeoFeatureModelSerializer(GeoFeatureModelSerializer): def to_internal_value(self, data): result = super().to_internal_value(data) result[self.Meta.geo_field] = GEOSGeometry( json.dumps(result[self.Meta.geo_field]) ) return result
@nemesifier is it in the scope of this library to merge such a fix ? I am willing to make a PR supporting this use-case.
A quick solution is to redefine a new serializer class that correctly instantiate a GEOSGeometry.
Here is such a class :
class InstantiatingGeoFeatureModelSerializer(GeoFeatureModelSerializer): def to_internal_value(self, data): result = super().to_internal_value(data) result[self.Meta.geo_field] = GEOSGeometry( json.dumps(result[self.Meta.geo_field]) ) return result
Ok, the best way to solve this is to implement "validate_<your_geometry_field>" and to instatiate a GEOSGeometry there.
For example :
class PolySerializer(GeoFeatureModelSerializer):
class Meta:
model = Poly
geo_field = "geom"
fields = ("id", "name", "created_at")
read_only_fields = ["id"]
def validate_geom(self, value):
value = GEOSGeometry(json.dumps(value))
# The following line is not related to this issue, but it's usefull if your geometry field is a multi-collection
if isinstance(value, Polygon):
value = MultiPolygon(value)
return value