Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Paginate within an action in Django Rest Framework

Good afternoon community, I have a question about the Django rest framework page. In this case, I manage to do it in the viewset, but in a class action I have not been able to achieve it.

Attached are images of the responses in the Django rest framework:

Response in viewset

Action:

Response in class action

class PostPageNumberPagination(PageNumberPagination):
    page_size=10

class InterfacesViewSet(viewsets.ModelViewSet):
     
    queryset=Interfaces.objects.all()
    serializer_class=InterfaceSerializer
    pagination_class=PostPageNumberPagination

# La siguiente funcion es un decorador(funciones extra) de la clase RegistrosViewSet para poder manipular los datos que voy a presentar de acuerdo a la URL que se le asigne con el url_path
# El siguiente action actua para poder presentar todos los datos de todos los objetos
    @action(methods=['get'],detail=False,url_path='registros-data-table',url_name='registros_data_table')
    def registros_data_table(self, request):
            paginator=PostPageNumberPagination
            return Response(
                    {
                'id_interface':interface.id_interface,
                'id_EquipoOrigen':interface.id_EquipoOrigen_id,
                'EquipoOrigen':interface.id_EquipoOrigen.nombre,
                'LocalidadOrigen':interface.id_EquipoOrigen.localidad,
                'CategoriaOrigen':interface.id_EquipoOrigen.categoria,
                'id_PuertoOrigen':interface.id_PuertoOrigen_id,
                'PuertoOrigen':interface.id_PuertoOrigen.nombre,
                'estatus':interface.estatus,
                'etiqueta_prtg':interface.etiqueta_prtg,
                'grupo':interface.grupo,
                'if_index':interface.if_index,
                'bw':interface.bw,
                'bw_al':interface.bw_al,
                'id_prtg':interface.id_prtg,
                'ospf':interface.ospf,
                'description':interface.description,
                'id_EquipoDestino':interface.id_EquipoDestino_id,
                'EquipoDestino':interface.id_EquipoDestino.nombre,
                'LocalidadDestino':interface.id_EquipoDestino.localidad,
                'CategoriaDestino':interface.id_EquipoDestino.categoria,
                'id_PuertoDestino':interface.id_PuertoDestino_id,
                'PuertoDestino':interface.id_PuertoDestino.nombre,
                'ultima_actualizacion':interface.ultima_actualizacion,
                    }
                for interface in Interfaces.objects.all()
            )

Update: I made the method provided by the friend @bdoubleu but I get that the objects are not being paginated, that is to say in all the pages the total number of objects appears.

Screenshot without pagination

Screenshot with pagination, but it does not have an effect

like image 661
Cesar Justo Avatar asked Jul 26 '19 15:07

Cesar Justo


1 Answers

Similar to how you would do it for list(...) for ModelViewSets.

rest_framework.viewsets/ModelViewSet.html#list

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

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

It would just be

class InterfacesViewSet(viewsets.ModelViewSet):
    queryset=Interfaces.objects.all()
    serializer_class=InterfaceSerializer
    pagination_class=PostPageNumberPagination

    @action(methods=['get'],detail=False,url_path='registros-data-table',url_name='registros_data_table')
    def registros_data_table(self, request):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)

        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

Output would look like

{
    "count": 1023
    "next": "https://api.example.org/accounts/?page=5",
    "previous": "https://api.example.org/accounts/?page=3",
    "results": [
       …
    ]
}

This is something I am using myself as a mixin for paginated responses. Throw this guy on anything with a GenericViewSet.

class PaginatedResponseMixin(object):
    def paginated_response(self, queryset=[], serializer_class=None, pagination_class=None,
                           context={}, **kwargs):
        context['request'] = self.request
        queryset = queryset or self.queryset
        pagination_class = pagination_class or self.pagination_class
        paginator = pagination_class()
        serializer_class = serializer_class or self.get_serializer_class()
        for k, v in kwargs.items():
            setattr(paginator, k, v)
        page = paginator.paginate_queryset(queryset, self.request, view=self)
        serializer = serializer_class(page, context=context, many=True)
        return paginator.get_paginated_response(serializer.data)

kwargs uses drf argument for the paginator.

Use like

class PostViewSet(PaginatedResponseMixin, viewsets.ModelViewSet):
    queryset = ...
    serializer = ...

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        return self.paginated_response(queryset, self.get_serializer_class(), CursorPagination, page_size=4)
        return self.paginated_response() # takes default from ViewSet
        return self.paginated_response(page_size=4) # takes partial arguments
like image 182
zyeek Avatar answered Sep 23 '22 04:09

zyeek