drf-yasg: Show custom pagination for ListAPIView in Swagger docs

2.9k views Asked by At

I have following ListAPIView and custom pagination class in Django REST framework:

views.py

class pricetrend(generics.ListAPIView):
    queryset = Variants.objects.annotate(timestamp=TruncMonth('variantTimestamp')).values('timestamp').annotate(average_price=Avg('price'))
    serializer_class = PricetrendSerializer
    pagination_class = PricesPagination

custom pagination class

class PricesPagination(PageNumberPagination):
    page_size = 10
    page_size_query_param = 'page_size'

    def get_paginated_response(self, data):
        prices = [dict(item)['average_price'] for item in data]
        try:
            total_average_price = sum(prices)/ len(prices)
        except Exception as e:
            total_average_price = 0
        return Response({
            'count': self.page.paginator.count,
            'next': self.get_next_link(),
            'previous': self.get_previous_link(),
            'total_average_price': round(total_average_price),
            'results': data,
        })

Currently, I am trying to figure out how the custom pagination class can be shown in the Swagger API docs generated by drf-yasg.

I already customized the PaginatorInspector from drf_yasg.inspectors but don't know where I need to put that in order to use it for the above mentioned ListAPIView.

custom PaginatorInspector

from drf_yasg.inspectors import PaginatorInspector
from drf_yasg import openapi


class LimitOffsetPaginatorInspectorClass(PaginatorInspector):

    def get_paginated_response(self, paginator, response_schema):
        """
        :param BasePagination paginator: the paginator
        :param openapi.Schema response_schema: the response schema that must be paged.
        :rtype: openapi.Schema
        """

        return openapi.Schema(
            type=openapi.TYPE_OBJECT,
            properties=OrderedDict((
                ('count', openapi.Schema(type=openapi.TYPE_INTEGER) if has_count else None),
                ('next', openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_URI, x_nullable=True)),
                ('previous', openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_URI, x_nullable=True)),
                ('total_average_price', openapi.Schema(type=openapi.TYPE_INTEGER)),
                ('results', response_schema),
            )),
            required=['results']
        )

As I am using other ListAPIViews with the default pagination class specified in settings.py, the custom pagination class should only be used for the ListAPIView "pricetrend".

1

There are 1 answers

0
DevDjas On BEST ANSWER

Solved it as follows:

  1. Creating custom Paginator Inspector

Paginator Inspector

class LimitOffsetPaginatorInspectorClass(PaginatorInspector):

def get_paginated_response(self, paginator, response_schema):
    """
    :param BasePagination paginator: the paginator
    :param openapi.Schema response_schema: the response schema that must be paged.
    :rtype: openapi.Schema
    """

    return openapi.Schema(
        type=openapi.TYPE_OBJECT,
        properties=OrderedDict((
            ('count', openapi.Schema(type=openapi.TYPE_INTEGER)),
            ('next', openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_URI, x_nullable=True)),
            ('previous', openapi.Schema(type=openapi.TYPE_STRING, format=openapi.FORMAT_URI, x_nullable=True)),
            ('total_average_price', openapi.Schema(type=openapi.TYPE_INTEGER)),
            ('results', response_schema),
        )),
        required=['results']
    )
  1. Overriding ListAPIView in order to be able to use @swagger_auto_schema to specify custom paginator inspector

views.py

class pricetrend(generics.ListAPIView):
    queryset = Variants.objects.annotate(timestamp=TruncMonth('variantTimestamp')).values('timestamp').annotate(average_price=Avg('price'))
    serializer_class = PricetrendSerializer
    pagination_class = PricesPagination
    @swagger_auto_schema(pagination_class=PricesPagination, paginator_inspectors=[LimitOffsetPaginatorInspectorClass])
    def get(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        serializer = PricetrendSerializer(page, many=True)
        return self.get_paginated_response(serializer.data)