Skip to content

Commit

Permalink
bugfix GeometryFilter for GIS and django-filter #814
Browse files Browse the repository at this point in the history
  • Loading branch information
tfranzel committed Sep 23, 2022
1 parent 31bb14a commit 348a06e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 0 deletions.
17 changes: 17 additions & 0 deletions drf_spectacular/contrib/django_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,24 @@ def _get_schema_from_model_field(self, auto_schema, filter_field, model):
# potential side effects. Only after that fails, attempt to call
# get_queryset() to check for potential query annotations.
model_field = self._get_model_field(filter_field, model)

# this is a cross feature between rest-framework-gis and django-filter. Regular
# behavior needs to be sidestepped as the model information is lost down the line.
# TODO for now this will be just a string to cover WKT, WKB, and urlencoded GeoJSON
# build_geo_schema(model_field) would yield the correct result
if self._is_gis(model_field):
return build_basic_type(OpenApiTypes.STR)

if not isinstance(model_field, models.Field):
qs = auto_schema.view.get_queryset()
model_field = qs.query.annotations[filter_field.field_name].field
return auto_schema._map_model_field(model_field, direction=None)

def _is_gis(self, field):
try:
from django.contrib.gis.db.models import GeometryField
from rest_framework_gis.filters import GeometryFilter

return isinstance(field, (GeometryField, GeometryFilter))
except ImportError:
return False
37 changes: 37 additions & 0 deletions tests/contrib/test_rest_framework_gis.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,40 @@ class PlainViewset(mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.Ge
generate_schema(None, patterns=router.urls),
'tests/contrib/test_rest_framework_gis.yml'
)


@pytest.mark.contrib('rest_framework_gis', 'django_filter')
@mock.patch('drf_spectacular.settings.spectacular_settings.ENUM_NAME_OVERRIDES', {})
def test_geo_filter_set(no_warnings):
from django.contrib.gis.db.models import PointField
from django_filters import filters
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework_gis.filters import GeometryFilter
from rest_framework_gis.filterset import GeoFilterSet

class GeoRegionModel(models.Model):
slug = models.CharField(max_length=32)
geom = PointField()

class RegionFilter(GeoFilterSet):
slug = filters.CharFilter(field_name='slug', lookup_expr='istartswith')
contains_geom = GeometryFilter(field_name='geom', lookup_expr='contains')

class Meta:
model = GeoRegionModel
fields = ['slug', 'contains_geom']

class XSerializer(serializers.Serializer):
slug = serializers.CharField()

class XViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
serializer_class = XSerializer
queryset = GeoRegionModel.objects.none()
filterset_class = RegionFilter
filter_backends = [DjangoFilterBackend]

schema = generate_schema('/x', XViewset)
assert schema['paths']['/x/']['get']['parameters'] == [
{'in': 'query', 'name': 'contains_geom', 'schema': {'type': 'string'}},
{'in': 'query', 'name': 'slug', 'schema': {'type': 'string'}}
]

0 comments on commit 348a06e

Please sign in to comment.