Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: Cannot set GeoPoint SpatialProxy (POINT) with value of type: <class 'dict'> #284

Open
eruiz67 opened this issue Jun 24, 2023 · 4 comments

Comments

@eruiz67
Copy link

eruiz67 commented Jun 24, 2023

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:
imagen

{
    "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'>
@gbip
Copy link
Contributor

gbip commented Oct 18, 2023

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.

@gbip
Copy link
Contributor

gbip commented Oct 18, 2023

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

@gbip
Copy link
Contributor

gbip commented Oct 19, 2023

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.

@gbip
Copy link
Contributor

gbip commented Dec 19, 2023

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants