Skip to content

Commit

Permalink
Merge branch 'gis_related_fix'
Browse files Browse the repository at this point in the history
  • Loading branch information
tfranzel committed Sep 23, 2022
2 parents 0147d32 + 348a06e commit 514db9d
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 3 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
6 changes: 4 additions & 2 deletions drf_spectacular/contrib/rest_framework_gis.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

from drf_spectacular.drainage import warn
from drf_spectacular.extensions import OpenApiSerializerExtension, OpenApiSerializerFieldExtension
from drf_spectacular.plumbing import ResolvedComponent, build_array_type, build_object_type, get_doc
from drf_spectacular.plumbing import (
ResolvedComponent, build_array_type, build_object_type, follow_field_source, get_doc,
)


def build_point_schema():
Expand Down Expand Up @@ -210,7 +212,7 @@ def map_serializer_field(self, auto_schema, direction):
# robustly checking the proper condition is harder.
try:
model = self.target.parent.Meta.model
model_field = get_field_info(model).fields[self.target.source]
model_field = follow_field_source(model, self.target.source.split('.'))
return build_geo_schema(model_field)
except: # noqa: E722
warn(f'Encountered an issue resolving field {self.target}. defaulting to generic object.')
Expand Down
46 changes: 45 additions & 1 deletion tests/contrib/test_rest_framework_gis.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def test_rest_framework_gis(no_warnings, clear_caches):
GeometryCollectionField, GeometryField, LineStringField, MultiLineStringField,
MultiPointField, MultiPolygonField, PointField, PolygonField,
)
from rest_framework_gis.fields import GeometryField as SerializerGeometryField
from rest_framework_gis.pagination import GeoJsonPagination
from rest_framework_gis.serializers import GeoFeatureModelSerializer

Expand All @@ -34,6 +35,10 @@ class GeoModel(models.Model):
field_multilinestring = MultiLineStringField()
field_geometrycollection = GeometryCollectionField()

class GeoModel2(models.Model):
related_model = models.OneToOneField(GeoModel, on_delete=models.DO_NOTHING)
field_point = PointField()

router = routers.SimpleRouter()

# all GIS fields as GeoJSON in singular and list form
Expand All @@ -58,9 +63,11 @@ class XViewset(mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.Generi

# plain serializer with GIS fields but without restructured container object
class PlainSerializer(serializers.ModelSerializer):
field_gis_related = SerializerGeometryField(source="geomodel2.field_point")

class Meta:
model = GeoModel
fields = ['id', 'field_random1', 'field_random2', 'field_gis_plain']
fields = ['id', 'field_random1', 'field_random2', 'field_gis_plain', 'field_gis_related']

class PlainViewset(mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
serializer_class = PlainSerializer
Expand All @@ -80,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'}}
]
18 changes: 18 additions & 0 deletions tests/contrib/test_rest_framework_gis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -998,8 +998,26 @@ components:
- 77.5933
minItems: 2
maxItems: 3
field_gis_related:
type: object
properties:
type:
type: string
enum:
- Point
coordinates:
type: array
items:
type: number
format: float
example:
- 12.9721
- 77.5933
minItems: 2
maxItems: 3
required:
- field_gis_plain
- field_gis_related
- field_random1
- field_random2
- id
Expand Down

0 comments on commit 514db9d

Please sign in to comment.