web-dev-qa-db-fra.com

Django Rest Framework: activer la pagination sur un ViewSet (comme la pagination ModelViewSet)

J'ai un ViewSet comme celui-ci pour répertorier les données des utilisateurs:

class Foo(viewsets.ViewSet):

    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

Je veux activer la pagination comme la pagination par défaut pour ModelViewSet:

{
    "count": 55,
    "next": "http://myUrl/?page=2",
    "previous": null,
    "results": [{...},{...},...,{...}]
}

Le document officiel dit:

La pagination n'est effectuée automatiquement que si vous utilisez les vues ou les ensembles de vues génériques

... mais mon jeu de résultats n'est pas du tout paginé. Comment puis-je le paginer?

30
floatingpurr

La pagination n'est effectuée automatiquement que si vous utilisez les vues ou les ensembles de vues génériques

Le premier barrage routier traduit les documents en anglais. Ce qu'ils avaient l'intention de transmettre, c'est que vous souhaitiez un ensemble de vues générique. Les ensembles de vues génériques s'étendent de ApiViews génériques qui ont des méthodes de classe supplémentaires pour paginer les ensembles de requêtes et les réponses.

De plus, vous fournissez votre propre méthode list, mais le processus de pagination par défaut est en fait géré par le mixin :

class ListModelMixin(object):
    """
    List a queryset.
    """
    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)

La solution simple, utilisez le code framework:

class Foo(mixins.ListModelMixin, viewsets.GenericViewSet):
    queryset = User.objects.all()
    serializer = UserSerializer

La solution la plus complexe serait si vous avez besoin d'une méthode list personnalisée, alors vous devriez l'écrire comme bon vous semble mais dans le style de l'extrait de code mixin ci-dessus.

35
Mark Galloway

Pour ceux qui utilisent DRF 3.1 ou supérieur, ils changent la façon dont la pagination est gérée par défaut. Voir http://www.Django-rest-framework.org/topics/3.1-announcement/ pour plus de détails.

Maintenant, si vous souhaitez activer la pagination pour un ModelViewSet, vous pouvez le faire globalement en définissant dans votre fichier settings.py:

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100
}

Ou si vous le souhaitez uniquement pour un ModelViewSet, vous pouvez définir manuellement la pagination_class pour cet ensemble de vues uniquement.

from rest_framework.pagination import PageNumberPagination

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 100
    page_size_query_param = 'page_size'
    max_page_size = 1000

class FooViewSet(viewsets.ModelViewSet):
    pagination_class = StandardResultsSetPagination

Cela vous permet également de modifier la façon dont la pagination est gérée pour cet ensemble de vues uniquement.

DRF 3.1 a également introduit de nouveaux types de schémas de pagination par défaut que vous pouvez utiliser tels que LimitOffset et Cursor.

28
jeffjv

Essayez de fournir une variable de classe

paginate_by = 10 #This will paginate by 10 results per page.

Créez un ViewSet personnalisé qui n'effectue que list comme votre cas ici.

class ListModelViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    pass

Héritez maintenant de votre classe Foo avec cet ensemble de vues personnalisé

class Foo(ListModelViewSet):

    paginate_by = 10

    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

Cela devrait vous aider à faire fonctionner la pagination.

3
Arpit Goyal

Pagination dans DRF à l'aide des ensembles de vues et de la liste

Ici, j'ai géré une exception Si la page est vide, elle affichera des enregistrements vides

En définissant définir la taille de la page, cette taille de page est globale et elle est utilisée par paginator_queryset en vue

REST_FRAMEWORK = {'PAGE_SIZE': 10,}

Au vu de rest_framework, importez les mixins, les ensembles de vues

class SittingViewSet(viewsets.GenericViewSet,
    mixins.ListModelMixin):

    serializer_class = SittingSerializer
    queryset = Sitting.objects.all()
    serializer = serializer_class(queryset, many=True)

    def list(self, request, *args, **kwargs):
        queryset =self.filter_queryset(Sitting.objects.all().order_by('id'))

        page = request.GET.get('page')

        try: 
            page = self.paginate_queryset(queryset)
        except Exception as e:
            page = []
            data = page
            return Response({
                "status": status.HTTP_404_NOT_FOUND,
                "message": 'No more record.',
                "data" : data
                })

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

        # serializer = self.get_serializer(queryset, many=True)
        return Response({
            "status": status.HTTP_200_OK,
            "message": 'Sitting records.',
            "data" : data
        })

**> Remarque: Si vous n'utilisez pas Order_by, il affichera une exception car cette liste

donne une liste non ordonnée. **

2
Vinay Kumar

Une variation légèrement plus simple sur cette réponse si vous voulez une pagination pour un ViewSet particulier, mais n'avez pas besoin de personnaliser la taille de la page:

REST_FRAMEWORK = {
    'PAGE_SIZE': 100
}

class FooViewSet(viewsets.ModelViewSet):
    pagination_class = PageNumberPagination
1
morningstar