-->

How can I use pagination_class in django-rest-fram

2020-08-12 18:27发布

问题:

My pagination Class

class ArticleListPagination(PageNumberPagination):
    page_size = 2
    page_size_query_param = 'page_size'

My Article View Class

class Article(generics.GenericAPIView):

    queryset = Articles.objects.all()
    serializer_class = ArticlesSerializer
    pagination_class = ArticleListPagination

def get(self, request):
    queryset = self.get_queryset()
    serializer = ArticlesSerializer(queryset, many=True)
    return Response(serializer.data, status=status.HTTP_200_OK)

I am able to use custom pagination class using this

def get(self, request):
    queryset = self.get_queryset()
    page = ArticleListPagination()
    new = page.paginate_queryset(queryset, request)
    serializer = ArticlesSerializer(new, many=True)
    return Response(serializer.data, status=status.HTTP_200_OK)

Is it the proper way to use ArticleListPagination? If I have stated in my class that my pagination class is ArticleListPagination, why it is not changing the return queryset object.

回答1:

for django_rest_framework 3.0.x (or below):

You can extends the rest_framework.mixins.ListModelMixin directly, or you imlement the get or list method similar to that.

Of course generics.GenericAPIView is also needed.

def list(self, request, *args, **kwargs):
    queryset = self.filter_queryset(self.get_queryset())
    page = self.paginate_queryset(queryset)
    if page is not None:
        # get_paginaion_serializer will read your DEFAULT_PAGINATION_SERIALIZER_CLASS 
        # or view.pagination_serializer_class 
        # we will talk the two variable later
        serializer = self.get_pagination_serializer(page)
    else:
        serializer = self.get_serializer(queryset, many=True)
    return Response(serializer.data)

if you wanna config it "global", you can config in your settings.py

REST_FRAMEWORK = {
    # ...
    'DEFAULT_PAGINATION_SERIALIZER_CLASS': 'YourCustomPaginationSerializer',
    # ...
}

if you just wanna set to the specific view:

the attribute is pagination_serializer_class instead of pagination_class.

class MyView(generics.GenericAPIView):
    pagination_serializer_class = YourCustomPaginationSerializerClass

for django_rest_framework 3.1.x:

it's a slightly different, you can check the docs first. 3.1 Announcement , Pagination Docs

You can extends the rest_framework.mixins.ListModelMixin directly, or you imlement the get method similar to that.

Of course generics.GenericAPIView is also needed.

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)

if you wanna config it "global", you can config in your settings.py

REST_FRAMEWORK = {
    # ...
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'

    # ...
}

if you just wanna set to the specific view:

class MyView(generics.GenericAPIView):
    pagination_class = YourCustomPaginationClass


回答2:

You can use your custom pagination in viewset and changed on custom view

pagination.py

class OneByOneItems(pagination.PageNumberPagination):
    page_size = 2

    def get_paginated_response(self, data):
        return Response(OrderedDict([
             ('lastPage', self.page.paginator.count),
             ('countItemsOnPage', self.page_size),
             ('current', self.page.number),
             ('next', self.get_next_link()),
             ('previous', self.get_previous_link()),
             ('results', data)
         ]))

views.py

class LectionViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = LectionCourse.objects.all().order_by('-created_at')
    serializer_class = LectionSerializer

    @list_route(methods=['get'], url_path='get-lections/(?P<pk>[^/]+)')
    def get_lection(self, request, pk):
        self.pagination_class = OneByOneItems
        queryset = self.filter_queryset(self.queryset.filter(course=pk))
        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)   

serializers.py

class CourseSerializer(serializers.ModelSerializer):
    author = UserCreatorSerializer(many=True)
    project = ProjectSerializer(many=True)

    class Meta:
        model = Course
        fields = ('id', 'theme', 'author', 'project')


class LectionSerializer(serializers.HyperlinkedModelSerializer):
    choose_course = CourseSerializer(source='course')

    class Meta:
        model = LectionCourse
        fields = ('id', 'title', 'video', 'preview_description', 'number', 'choose_course')


回答3:

I prefer to use Custom pagination as it will allow you modify your response according to your requirements. This method doesn't require much effort.

Below is my code for this... Hope this will be helpful.

custom_pagination.py

from rest_framework import status
from rest_framework.pagination import LimitOffsetPagination
from rest_framework.response import Response

class CustomPagination(LimitOffsetPagination):
def get_paginated_response(self, data):
    return Response({
        "status": True,
        "code": status.HTTP_200_OK,
        'next': self.get_next_link(),
        'previous': self.get_previous_link(),
        'count': self.count,
        'results': data
    })

In your view all you need to do is to call two functions, i-e paginate_queryset and the one you created in your pagination class get_paginated_response. "pagination_queryset" takes queryset as parameter and than pass that result to your serializer, finally call "get_paginated_response" which takes serialized data as parameter and in result return response.

page = self.paginate_queryset(query_set)
serializer_class = <Your Serializer>(page, many=True,)
return self.get_paginated_response(serializer_search_user.data)

Finally declare your custom serialization class in "settings.py".

REST_FRAMEWORK = {
      'DEFAULT_PAGINATION_CLASS':'<your_app>.<your_peckage>.custom_pagination.CustomPagination',
      'PAGE_SIZE': 5
}