Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: pagination on APIView(Post) #575

Open
mke21 opened this issue Apr 14, 2020 · 4 comments
Open

Question: pagination on APIView(Post) #575

mke21 opened this issue Apr 14, 2020 · 4 comments

Comments

@mke21
Copy link

mke21 commented Apr 14, 2020

Hi,

Is it possible to do pagination on a post in an APIView? I don't seem to understand how that could be done. I've got the following:

class LargeResultPagination(PageNumberPagination):
    """
    Paginator for all apis
    """
    page_size = 100000
    max_page_size = 100000
    page_size_query_param = 'page_size'

class Data(APIView):
    """
    Demo of my view
    """
    pagination_class = LargeResultPagination

    @swagger_auto_schema(
        operation_description='...,
        request_body=BodySerializer,
        responses={200: ReturnSerializer(
             many=True
        )},
        pagination_class=LargeResultPagination,
        paginator_inspectors=[PaginatorInspector]
    )
    def post(self, request, version, format=None):
         ...

But the swagger page doesn't show any pagination in the responses model. What am I understanding wrong?

@ghost
Copy link

ghost commented Nov 12, 2020

I also need answer for this problem, in the documents mentioned that paginator_inspectors is the only way to add pagination to the response example, but this case it doesn't seem to work with APIView(even on GET request).

@tuenut
Copy link

tuenut commented May 25, 2021

I have the same problem - in my case i have custom serializer in list-action in my ModelViewSet, that is different from the serializer_class. I use swagger_auto_schema same way

class SomeViewSet(viewsets.ModelViewSet):
    serializer_class = SomeSerializer

    ...

    @swagger_auto_schema(responses={200: SomeCustomSerializer(many=True)})
    def list(self, request):
        ...

But in generated swagger docs i see just a list of data from SomeCustomSerialaizer, not wrapped in DEFAULT_PAGINATION_CLASS: rest_framework.pagination.PageNumberPagination. I also use the default DEFAULT_PAGINATOR_INSPECTORS settings.

It seems when i specify responses, drf-yasg ignores default pagination settings. Also explicit indication on pginator inspectors in swagger_auto_schema does not help.

@tuenut
Copy link

tuenut commented May 25, 2021

I have sort of fix for that situation.

tuenut@d20c44a

But i have not tested that solution and can say what ripple it can produce. You can crea your own subclass of SwaggerAutoSchema and override that method, and then use that subclass like as

@swagger_auto_schema(
    auto_schema=YourOwnSubclassOfSwaggerAutoSchema, 
    responses={200: SomeCustomSerializer(many=True)}
)
def list(self, request):
    ...

@2mitrij
Copy link

2mitrij commented Jul 4, 2021

My solution for this. Only for APIView. Works with any methods of APIView: GET, POST, PATCH, PUT, DELETE.

from drf_yasg import openapi
from drf_yasg.utils import guess_response_status
from drf_yasg.inspectors import SwaggerAutoSchema


class CustomSwaggerAutoSchema(SwaggerAutoSchema):

    def get_responses(self):
        response_serializers = self.get_response_serializers()
        response_schemas = self.get_response_schemas(response_serializers)

        paginator = self.overrides.get('paginator', None)
        if paginator and self.has_list_response():
            method = self.method.lower()
            default_response_status = str(guess_response_status(method))
            if default_response_status in response_schemas:
                response_schemas[default_response_status] = openapi.Response(
                    description=response_schemas[default_response_status].description,
                    schema=self.get_paginated_response(
                        response_schemas[default_response_status].schema
                    )
                )

        return openapi.Responses(responses=response_schemas)

    def get_paginated_response(self, response_schema):
        return self.probe_inspectors(self.paginator_inspectors, 'get_paginated_response',
                                     self._get_paginator(), response_schema=response_schema)

    def get_pagination_parameters(self):
        if not self.should_page():
            return []

        return self.probe_inspectors(self.paginator_inspectors, 'get_paginator_parameters',
                                     self._get_paginator()) or []

    def should_page(self):
        return self._get_paginator() and self.has_list_response()

    def _get_paginator(self):
        return self.overrides.get('paginator') or getattr(self.view, 'paginator', None)

In settings:

SWAGGER_SETTINGS = {
    ...
    'DEFAULT_AUTO_SCHEMA_CLASS': 'website_apps.api.utils.swagger.CustomSwaggerAutoSchema',
}

In view code:

class EntityListView(APIView):
    class ListPagination(pagination.CursorPagination):
        page_size = 20    

    @swagger_auto_schema(
        operation_description=_('Returns entity list with pagination'),
        query_serializer=EntityListQueryFilter(),
        responses={
            200: openapi.Response(
                description=_('Paginated entity list'),
                schema=EntityOutputSerializer(many=True)
            )
        },
        paginator=ListPagination()
    )
    def get(self, request):
        serializer = serializers.EntityListQueryFilter(data=request.query_params)
        serializer.is_valid(raise_exception=True)

        entities = get_entities(**serializer.validated_data)
        paginator = self.ListPagination()
        entities = paginator.paginate_queryset(entities, request)

        serializer = EntityOutputSerializer(entities, many=True)
        return paginator.get_paginated_response(serializer.data)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants