5

In our API we have an endpoint to list locations. We allow filtering on location type, and we allow multiple values for this filter. For example:

GET /location/?type=hotel&type=airport

For filtering we are using django-filter. However, drf-yasg doesn't seem to correctly generate the schema for this parameter.

The view class can be boiled down to this:

from rest_framework.generics import ListAPIView
from .models import Location
from .serializers import LocationListSerializer
from .filters import LocationFilterSet
from django_filters.rest_framework import DjangoFilterBackend

class LocationListView(ListAPIView):
    queryset = Location.objects.all()
    serializer_class = LocationListSerializer
    filter_backends = (
        DjangoFilterBackend,
    )
    filter_class = LocationFilterSet

and the filter class looks like this:

from django_filters import rest_framework as filters
from .models import Location

class LocationFilterSet(filters.FilterSet):
    type = filters.MultipleChoiceFilter(choices=Location.TYPE_CHOICES)

    class Meta:
        model = Location
        fields = (
            'type',
        )

This view works as intended - the following test passes:

from django.test import TestCase
from django.urls import reverse
from rest_framework import status
from .models import Location

class TestLocationView(TestCase):
    def test_filter_by_multiple_types(self):
        Location.objects.create(type='airport')
        Location.objects.create(type='hotel')
        Location.objects.create(type='home')
        response = self.client.get('/location/?type=hotel&type=airport')
        self.assertEqual(len(response.data), 2)

I'd expect the generated yaml for this parameter to look like this:

parameters:
- name: type
  in: query
  description: ''
  required: false
  schema:
      type: array
      items:
          type: string
  explode: true

but instead, it looks like this:

- name: type
  in: query
  description: ''
  required: false
  type: string

Is this a limitation of drf-yasg?

It's not possible to use swagger_auto_schema's query_serializer since it doesn't allow overriding the schemas generated by the filter backends.

This seems to happen because django_filters.rest_framework.backends.DjangoFilterBackend.get_coreschema_field only outputs two field types, number and strings. I went ahead and overrode that method, however, it then throws errors in drf_yasg.inspectors.query.CoreAPICompatInspector.coreapi_field_to_parameter, doesn't accept the array type.

DMFerrer
  • 73
  • 1
  • 10
  • 1
    I ended up using a CharFilter with a method argument, splitting the string by comma, etc. There's a issue for this: https://github.com/swagger-api/swagger-ui/issues/118 – daigorocub Apr 14 '20 at 21:57

0 Answers0