drf_yasg only renders filterset parameters on list view

878 Views Asked by At

I have defined a filterset for a DRF ViewSet. drf_yasg correctly renders all the filterset fields as parameters in Swagger for the list endpoint, but not for any other endpoints.

Any idea why?

views.py:

from rest_framework import mixins, viewsets

from django_filters import rest_framework as filters

from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema

from my_app.models import MyModel
from my_app.serializers import MySerializer

class MyFilterSet(filters.FilterSet):
    class Meta:
        model = MyModel
        fields = {
            "status",
        }
class MyViewSet(
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    viewsets.GenericViewSet,
):

    filter_backends = (filters.DjangoFilterBackend, )
    filterset_class = MyFilterSet
    queryset = MyModel.objects.all()
    serializer_class = MySerializer
2

There are 2 best solutions below

2
On

List is only place where filters are actually used (see here)

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        ...

There is nothing to filter on create/update/delete since there are no multiple results. Same goes for retrieve, you are fetching an object by id, so filtering single result doesn't make any sense.

0
On

While it's true that other methods beyond list employ filter_queryset, drf-yasg will only auto populate the filter parameters in the event that it's a GET method that returns a list of objects. You can see this decision in the inspectors.ViewInspector file.

If you want to see them I can think of two options

  1. Extend the SwaggerAutoSchema class and allow other HTTP verbs
  2. Add a decorator to the ViewSet to include some manual parameters. For example, to add it to the retrieve method.
@method_decorator(
    name="retrieve", 
    decorator=swagger_auto_schema(
        manual_parameters=[openapi.Parameter("field", openapi.IN_QUERY, description="filter on field", type=openapi.TYPE_STRING)],
    )
)
class MyViewSet(
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    viewsets.GenericViewSet,
):
...