openwisp/django-rest-framework-gis

GDALException raised when providing bad input to GeometryFilter

Open

#187 opened on Feb 7, 2019

 (5 comments) (0 reactions) (0 assignees)Python (204 forks)batch import
bughacktoberfest

Repository metrics

Stars
 (1,053 stars)
PR merge metrics
 (Avg merge 1h 11m) (1 merged PR in 30d)

Description

My setup it is something along the lines of this:

class Location(models.Model):
    point = models.PointField(geography=True)


class LocationFilterSet(filters.FilterSet):

    within = GeometryFilter(
        field_name="point", srid=4326, method="filter_within"
    )

    class Meta:
        model = Location
        fields = ["within"]

    def filter_within(self, qs, name, value):
        return qs.filter(**{f"{name}__dwithin": (value, Distance(1))})

class LocationViewSet(ModelViewSet):
    queryset = Location.objects.all()
    filter_backends = (django_filters.DjangoFilterBackend, )
    filter_class = LocationFilterSet

When I query the filter providing invalid input http://localhost:8000/api/locations/?within={"type":"Feature","I am not valid":"1,1,1"}

I get the following exception:

  return self.application(environ, start_response)
File "/var/www/.venv/lib/python3.7/site-packages/django/core/handlers/wsgi.py", line 142, in __call__
  response = self.get_response(request)
File "/var/www/.venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 78, in get_response
  response = self._middleware_chain(request)
File "/var/www/.venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
  response = response_for_exception(request, exc)
File "/var/www/.venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
  response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/var/www/.venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 125, in handle_uncaught_exception
  return debug.technical_500_response(request, *exc_info)
File "/var/www/.venv/lib/python3.7/site-packages/django_extensions/management/technical_response.py", line 37, in null_technical_500_response
  six.reraise(exc_type, exc_value, tb)
File "/var/www/.venv/lib/python3.7/site-packages/six.py", line 692, in reraise
  raise value.with_traceback(tb)
File "/var/www/.venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
  response = get_response(request)
File "/var/www/.venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 126, in _get_response
  response = self.process_exception_by_middleware(e, request)
File "/var/www/.venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 124, in _get_response
  response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/var/www/.venv/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
  return view_func(*args, **kwargs)
File "/var/www/.venv/lib/python3.7/site-packages/rest_framework/viewsets.py", line 116, in view
  return self.dispatch(request, *args, **kwargs)
File "/var/www/.venv/lib/python3.7/site-packages/rest_framework/views.py", line 495, in dispatch
  response = self.handle_exception(exc)
File "/var/www/.venv/lib/python3.7/site-packages/rest_framework/views.py", line 455, in handle_exception
  self.raise_uncaught_exception(exc)
File "/var/www/.venv/lib/python3.7/site-packages/rest_framework/views.py", line 492, in dispatch
  response = handler(request, *args, **kwargs)
File "/var/www/.venv/lib/python3.7/site-packages/rest_framework/mixins.py", line 40, in list
  queryset = self.filter_queryset(self.get_queryset())
File "/var/www/.venv/lib/python3.7/site-packages/rest_framework/generics.py", line 152, in filter_queryset
  queryset = backend().filter_queryset(self.request, queryset, self)
File "/var/www/.venv/lib/python3.7/site-packages/rest_framework_json_api/django_filters/backends.py", line 134, in filter_queryset
  return super(DjangoFilterBackend, self).filter_queryset(request, queryset, view)
File "/var/www/.venv/lib/python3.7/site-packages/django_filters/rest_framework/backends.py", line 94, in filter_queryset
  if not filterset.is_valid() and self.raise_exception:
File "/var/www/.venv/lib/python3.7/site-packages/django_filters/filterset.py", line 206, in is_valid
  return self.is_bound and self.form.is_valid()
File "/var/www/.venv/lib/python3.7/site-packages/django/forms/forms.py", line 185, in is_valid
  return self.is_bound and not self.errors
File "/var/www/.venv/lib/python3.7/site-packages/django/forms/forms.py", line 180, in errors
  self.full_clean()
File "/var/www/.venv/lib/python3.7/site-packages/django/forms/forms.py", line 381, in full_clean
  self._clean_fields()
File "/var/www/.venv/lib/python3.7/site-packages/django/forms/forms.py", line 399, in _clean_fields
  value = field.clean(value)
File "/var/www/.venv/lib/python3.7/site-packages/django/contrib/gis/forms/fields.py", line 63, in clean
  geom = super().clean(value)
File "/var/www/.venv/lib/python3.7/site-packages/django/forms/fields.py", line 147, in clean
  value = self.to_python(value)
File "/var/www/.venv/lib/python3.7/site-packages/django/contrib/gis/forms/fields.py", line 42, in to_python
  value = GEOSGeometry(value)
File "/var/www/.venv/lib/python3.7/site-packages/django/contrib/gis/geos/geometry.py", line 705, in __init__
  ogr = gdal.OGRGeometry.from_json(geo_input)
File "/var/www/.venv/lib/python3.7/site-packages/django/contrib/gis/gdal/geometries.py", line 161, in from_json
  return OGRGeometry(OGRGeometry._from_json(force_bytes(geom_input)))
File "/var/www/.venv/lib/python3.7/site-packages/django/contrib/gis/gdal/geometries.py", line 143, in _from_json
  ptr = capi.from_json(geom_input)
File "/var/www/.venv/lib/python3.7/site-packages/django/contrib/gis/gdal/prototypes/errcheck.py", line 84, in check_geom
  raise GDALException('Invalid geometry pointer returned from "%s".' % func.__name__)
django.contrib.gis.gdal.error.GDALException: Invalid geometry pointer returned from "OGR_G_CreateGeometryFromJson".

I've kind of fixed the issue by using the code below. This doesn't seem like a hugely eloquent solution though.

from django.contrib.gis import forms
from rest_framework_gis.filters import GeometryFilter as BaseGeometryFilter

class GeometryField(forms.GeometryField):
    """Catch GDALException."""

    def to_python(self, value):
        """Catch GDALException."""
        try:
            return super().to_python(value)
        except GDALException as e:
            raise forms.ValidationError("Invalid geometry value.")


class GeometryFilter(BaseGeometryFilter):
    """Catch GDALException."""

    field_class = GeometryField

Is there something I'm missing? I've read through the docs and check the issues and I can't seem to find a better solution.

Contributor guide