[Django] DRF-Pagination APIView

Cherry·2022년 2월 3일
0
post-thumbnail
post-custom-banner

지난 포스트에서는 viewset에서의 pagination을 소개했었다. 그러나 프로젝트를 진행하다 보면서 viewset을 사용하지 않고 커스텀하기 쉬운 APIview를 통해서 뷰를 짰다. 따라서 APIview에서는 다르게 pagination을 적용해줘야 했다.

1. Pagination import하기

PageNumberPagination이 가장 흔하기 때문에 PageNumberPagination을 사용할 것이다.
views.py

class MemoPagination(PageNumberPagination):
    page_size_query_param = 'limit'

우선 views에 PageNumberPagination를 import한다.

2. APIView에 pagination_class 설정하기

views.py

class MemoList(APIView):
    pagination_class = MemoPagination
    serializer_class = MemoSerializer
  def get(self, request, format=None, *args, **kwargs):
      instance = Memo.objects.all()
      serializer = self.serializer_class(instance, many=True)
      return Response(serializer.data, status=status.HTTP_200_OK)

pagination_class을 설정해주었지만 api 테스트를 해보면 아직 페이징이 적용되지 않을 것이다. APIView는 viewset과는 다르게 조금 더 추가를 해주어야 한다.

views.py

class MemoList(APIView):
    pagination_class = MemoPagination
    serializer_class = MemoSerializer
    @property
    def paginator(self):
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        else:
            pass
        return self._paginator
    def paginate_queryset(self, queryset):
        
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset,
                   self.request, view=self)
    def get_paginated_response(self, data):
        assert self.paginator is not None
        return self.paginator.get_paginated_response(data)
    def get(self, request, format=None, *args, **kwargs):
        instance = Memo.objects.all()
        page = self.paginate_queryset(instance)
        if page is not None:
            serializer = self.get_paginated_response(self.serializer_class(page,
 many=True).data)
        else:
            serializer = self.serializer_class(instance, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

이제 API에서 "page"나 "limit"이라는 키를 통해 query parameter로 넘겨주어서 페이징을 컨트롤할 수 있다.
그러나 페이징이 필요한 API가 여러개가 있다면 위와 같은 코드들은 수없이 반복 될 것이다. 따라서 단순히 반복 작업을 하기 보다는 mixin을 써주어서 코드를 단순화 할 수 있다.

3. Mixin 작성하기

pagination.py

class PaginationHandlerMixin(object):
    @property
    def paginator(self):
        if not hasattr(self, '_paginator'):
            if self.pagination_class is None:
                self._paginator = None
            else:
                self._paginator = self.pagination_class()
        else:
            pass
        return self._paginator
    def paginate_queryset(self, queryset):
        
        if self.paginator is None:
            return None
        return self.paginator.paginate_queryset(queryset,
                   self.request, view=self)
    def get_paginated_response(self, data):
        assert self.paginator is not None
        return self.paginator.get_paginated_response(data)

views.py

from rest_framework.pagination import PageNumberPagination
from .pagination import PaginationHandlerMixin


class MemoPagination(PageNumberPagination):
    page_size_query_param = 'limit'
    
class MemoList(APIView, PaginationHandlerMixin):
    pagination_class = MemoPagination
    serializer_class = MemoSerializer
    def get(self, request, format=None, *args, **kwargs):
        instance = Memo.objects.all()
        page = self.paginate_queryset(instance)
        if page is not None:
            serializer = self.get_paginated_response(self.serializer_class(page,
 many=True).data)
        else:
            serializer = self.serializer_class(instance, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)

완성!! API 테스트를 해봐도 정상적으로 잘 나온다!!❤

post-custom-banner

0개의 댓글