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.