I currently observe the behavior that a ModelSerializer does not validate if the geometry field is of the right geometry type. Hence, the serializer does not throw a validation error when it receives data of an unexpected geometry type but later runs into a TypeError that is thrown by Django when the data is saved to the database.
Example
# models.py
from django.db import models
from django.contrib.gis.db import models as gis_models
class PolygonModel(models.Model):
polygon = gis_models.PolygonField()
# serializer.py
from rest_framework import serializers
class PolygonSerializer(serializers.ModelSerializer):
class Meta:
model = PolygonModel
fields = "__all__"
# view.py
from rest_framework import viewsets
class PolygonViewSet(viewsets.ModelViewSet):
serializer_class = PolygonSerializer
queryset = PolygonModel.objects.all()
# urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register("polygons', PolygonViewSet)
urlpatterns = router.urls
If the /polygons end point would receive a POST/PUT request with the following body
File "/usr/local/lib/python3.10/site-packages/django/db/models/manager.py", line 87, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/usr/local/lib/python3.10/site-packages/django/db/models/query.py", line 656, in create
obj = self.model(**kwargs)
File "/usr/local/lib/python3.10/site-packages/django/db/models/base.py", line 546, in __init__
_setattr(self, field.attname, val)
File "/usr/local/lib/python3.10/site-packages/django/contrib/gis/db/models/proxy.py", line 76, in __set__
raise TypeError(
TypeError: Cannot set Plot SpatialProxy (POLYGON) with value of type: <class 'django.contrib.gis.geos.point.Point'>
However, for my opinion a ValidationError would be more appropriated to be raised.
Problem
I think the problem comes done to the field_mapping in the apps.py module which maps the GeoDjango fields to a generic GeometryField.
My idea would be to append a GeometryFieldValidator to validators list of the GeometryField:
class GeometryValidator:
def __init__(self, geom_type):
self.geom_type = geom_type
def __call__(self, value):
if value.geom_type != self.geom_type:
raise serializers.ValidationError("Wrong geometry type provided.", code="invalid")
class GeometryField(Field):
"""
A field to handle GeoDjango Geometry fields
"""
type_name = 'GeometryField'
def __init__(
self, precision=None, remove_duplicates=False, auto_bbox=False, geom_type=None, **kwargs
):
"""
:param auto_bbox: Whether the GeoJSON object should include a bounding box
"""
self.precision = precision
self.auto_bbox = auto_bbox
self.remove_dupes = remove_duplicates
super().__init__(**kwargs)
self.style.setdefault('base_template', 'textarea.html')
if geom_type:
self.validators.append(GeometryValidator(geom_type))
I have not thought about the specifics of the implementation. However, I would be open to work on a PR if the described behavior of raising a ValidationError is of interest for the community. Or do you think one should simply solve this by adding the described GeometryValidator manually to each ModelSerializer which contains a geometry field, i.e.:
# serializer.py
from rest_framework import serializers
class PolygonSerializer(serializers.ModelSerializer):
polygon = GeometryField(validators=[GeometryValidator])
class Meta:
model = PolygonModel
fields = "__all__"
I currently observe the behavior that a
ModelSerializer
does not validate if the geometry field is of the right geometry type. Hence, the serializer does not throw a validation error when it receives data of an unexpected geometry type but later runs into aTypeError
that is thrown by Django when the data is saved to the database.Example
If the
/polygons
end point would receive a POST/PUT request with the following bodythe following error would be raised by Django:
However, for my opinion a
ValidationError
would be more appropriated to be raised.Problem
I think the problem comes done to the
field_mapping
in theapps.py
module which maps the GeoDjango fields to a genericGeometryField
.https://github.com/openwisp/django-rest-framework-gis/blob/4f244d5d8a7ad5b453fd04f64150818d15123e01/rest_framework_gis/apps.py#L24-L35
Solution
My idea would be to append a
GeometryFieldValidator
tovalidators
list of theGeometryField
:I have not thought about the specifics of the implementation. However, I would be open to work on a PR if the described behavior of raising a
ValidationError
is of interest for the community. Or do you think one should simply solve this by adding the describedGeometryValidator
manually to eachModelSerializer
which contains a geometry field, i.e.:Happy to get your feedback on this :).