2015-08-03 12 views
13

Mam ViewSet jak ten na liście danych użytkowników:Django Reszta ramowa: kolej na paginacji na ViewSet (jak ModelViewSet paginacji)

class Foo(viewsets.ViewSet): 

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

chcę włączyć paginacji jak domyślnego paginacji dla ModelViewSet :

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

The official doc mówi:

Pagination is only performed automatically if you're using the generic views or viewsets

... ale moja resultset i nie jest w ogóle stronicowana. Jak mogę go paginować?

Odpowiedz

16

Pagination is only performed automatically if you're using the generic views or viewsets

Pierwsza blokada drogowa to tłumaczenie dokumentów na angielski. To, co zamierzali przekazać, to pragnienie ogólnego spojrzenia. Ogólne widoki mają rozszerzenie od generic ApiViews, które mają dodatkowe metody klasy do stronowania zestawów zapytań i odpowiedzi.

Dodatkowo, jesteś zapewnienie własną metodę list, ale domyślny proces paginacja jest faktycznie obsługiwane przez 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) 

Proste rozwiązanie, należy użyć kodu ramowej:

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

Bardziej złożone rozwiązanie byłoby, gdybyś potrzebował niestandardowej metody list, to powinieneś napisać to, jak uważasz, ale w stylu powyższego fragmentu kodu mixin.

3

Spróbuj zapewniając klasę zmiennej

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

utworzyć niestandardową ViewSet która wykonuje tylko list operację jako sprawy bo tu obecnie.

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

Teraz dziedziczą swoją klasę Foo z tym wykonane na zamówienie viewset

class Foo(ListModelViewSet): 

    paginate_by = 10 

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

ten powinien pomóc Ci pracę paginacji.

+0

dodałem 'paginate_by = 10' ale to nie działa. Jeśli zmienię 'class Foo (viewsets.ViewSet):' z 'class Foo (generics.ListCreateAPIView):' Otrzymuję ten błąd: _as_view() przyjmuje dokładnie 1 argument (3 dane) _ – floatingpurr

+1

czy przekazujesz dowolny argument do .as_view()? Po drugie dlaczego nie używasz 'ModelViewSet'? –

+0

Nie, nic do .as_views(). Nie używam 'ModelViewSet', ponieważ muszę zakodować pewną logikę, aby przefiltrować podzbiór mojego' zestawu zapytań' i dodać niektóre dane do zestawu wyników niezwiązanego z modelem użytkownika (ta logika jest pominięta w kodzie mojego pytania) – floatingpurr

17

Dla osób stosujących standard DRF 3.1 lub wyższy, zmieniają one domyślny sposób obsługi stronicowania. Aby uzyskać szczegółowe informacje, patrz http://www.django-rest-framework.org/topics/3.1-announcement/.

Teraz, jeśli chcesz włączyć stronicowanie na ModelViewSet można też zrobić to globalnie poprzez ustawienie w pliku settings.py:

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

lub jeśli po prostu chcesz go za jednego ModelViewSet można ręcznie ustawić pagination_class tylko dla tego widoku.

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 

Umożliwia to również modyfikację sposobu obsługi paginacji dla danego widoku.

DRF 3.1 wprowadza również nowe typy domyślnych schematów stronicowania, które można wykorzystać, takie jak LimitOffset i Cursor.

+0

Próbowałem sam, ale nie działa –

+0

Jeśli poprosisz o stronę 1 przy użyciu PageNumberPagination, a potem nowy to em zostanie dodany do listy, a następnie poprosisz o stronę2, ostatni element, który właśnie znalazłeś na stronie 1, pojawi się ponownie jako pierwszy element na stronie 2 (pokazany 2 razy z rzędu). CursorPagination jest znacznie bardziej zalecanym sposobem niż PageNumberPagination. CursorPagination utrzymuje odniesienie do obiektów i nie musi obliczać zawartości dla każdej strony. W celu realizacji zobacz https://stackoverflow.com/a/47657610/5881884 – DevB2F

1

Pagination w DRF użyciu viewsets i lista

Tutaj mam obchodzić wyjątek Jeśli strona jest pusta pokaże puste rekordy

Przy ustalaniu określić rozmiar strony, to rozmiar strony jest globalny i jest używany przez paginator_queryset w widoku

rEST_FRAMEWORK = { 'PAGE_SIZE' 10}

Biorąc z wstawek import rest_framework, viewsets

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 
     }) 

**>. Uwaga: Jeśli nie używać Order_by pokaże wyjątek, ponieważ lista ta

daje nieuporządkowaną listę **

+0

Możesz również odwiedzić https://stackoverflow.com/a/46173281/8231158 Dałem dwie odpowiedzi jeden wróg Viewset i inne jest dla widoku API. –