티스토리 뷰
지난번 검색을 통해 Django에 대해 큰 실망을 했을지도 모르겠지만(자동화처리라고 좋아했다가 왠지 뺨을 맞은것만 같은 기분이 들어서..) 페이징에 대해서 좀 썰을 풀어보려고 한다.
지난번 "검색과 페이징" 첫번째 이야기를 보면 페이징에서 제일 중요한 부분이 바로 전체 게시물 개수를 가져오는 거라고 했다.
왜냐하면 전체 게시물 개수를 가져올 수 있어야 보여줄 수 있는 전체 페이지를 계산해 낼 수 있어서다.
그래서 Restframework 메뉴얼을 좀 읽어봤다. 저번에 잠깐 Paginate 관련 항목을 본것 같은 기억이 나서.
이미지를 클릭하면 Pagination 페이지로 이동합니다.
역시 내 기억은 틀리지 않았어!(Filtering 다음에 있는데 기억못하면 뇌에 문제가 있는 것이 아닐까 라고 생각할 수도 있지만)
메뉴얼을 찬찬히 읽어보고 적용하는 방법을 배웠다. 그런데 말입니다. 여기에도 함정이 있었다는 사실을 알게 되는데........
일단 먼저 본론으로 들어가기 전에 기본적으로는 SETTINGS 설정을 통해 Pagination을 적용시킬 수 있는데 여기서는 그걸 다루지는 않을거다. 왜냐하면 그러면 설명할게 너무 많아지고 글을 쓰는 나도 힘이 드니까. 그리고 SETTINGS쪽에 적용하면 전반적으로 사용되는 전역적 설정을 의미하는데 나는 어떤 API에서는 Pagination 설정을 적용하기 싫을 때도 있고 어떤 API에서는 Pagination 설정을 사용하고 싶을 때가 있을 수도 있는데 전역적 설정이 "편리"를 위해서라면 괜찮을지 모르겠지만 글쎄.. 이런 기능 조차도 전역설정을 가능하게 하는건 개인적인 생각으로는 "과도한 친절"이 아닐까 생각했다.
그래서 전역적 설정에 대해서 나중에 포스팅 하긴하겠지만 미리 알고 싶은 사람은 API 문서를 참고하기를 바란다.
일단, Restframework 에서 제공하는 Pagination의 종류는 PageNumberPagination, LimitOffsetPagination, CursorPagination 3가지가 있다. 오늘은 PageNumberPagination에 대해서 알아보도록 하자.
이 페이징 클래스는 아주 단순하게도 API 상에 페이지 숫자를 Query String으로 같이 넘겨주면 해당 페이지만큼 검색해주는 기능을 제공한다. 아래의 코드를 이용해서 적용해보도록 하자.
from django.shortcuts import render
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.pagination import PageNumberPagination
from rest_framework.filters import SearchFilter
from rest_framework.response import Response
from .serializers import BoardTypeSerializer
from .models import BoardType
# Create your views here.
class BoardListCreateView(ListCreateAPIView):
name = "board-list-create"
serializer_class = BoardTypeSerializer
"""
페이징 클래스 적용
"""
pagination_class = PageNumberPagination
def get_queryset(self):
queryset = BoardType.objects.all()
return queryset
def list(self, request, *args, **kwargs):
queryset = self.set_filters( self.get_queryset(), request )
"""
paginate_queryset 내장 함수에 queryset 객채를 전달한다.
이때 paginator라는 페이징 클래스를 인스턴스화한 속성에
size_query_param을 "page_size"를 적용한다.
이는 한번에 보여줄 게시물의 갯수를 어떤 파라미터를 통해 전달하는지 설정하는 속성이다.
"""
self.paginator.page_size_query_param = "page_size"
page = self.paginate_queryset(queryset)
"""
page 객체가 존재한다면 get_paginated_response 내장함수를 이용해 응답한다.
200 Success로 응답한다.
"""
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)
def set_filters(self, queryset, request):
type = request.query_params.get('type', None)
description = request.query_params.get('description', None)
if type is not None:
queryset = queryset.filter(type=type)
if description is not None:
queryset = queryset.filter(description__contains=description)
return queryset
class BoardRetrieveUpdateDestroyAPIView(RetrieveUpdateDestroyAPIView):
name = "board-retrieve-update-destroy"
serializer_class = BoardTypeSerializer
queryset = BoardType.objects.all()
지난번에 만들어 두었던 board-type/view.py 파일을 위와 같이 수정하였다. 그리고 Post man을 통해 "http://localhost:8000/board-type/?page_size=10"으로 접속해보자.
이렇게 위와같이 무언가 속성들이 추가된 것을 확인할 수 있다. 아직 게시물이 두개밖에 없어서 그런것이니 board type을 조금 더 추가해서 다시 확인해보도록 하겠다.
그리고 브라우저를 열어 "http://localhost:8000/board-type/?page_size=3" 으로 접속해보자.
게시판 종류를 아무거나 입력을 했는데 막상 입력하려니 뭘 입력하기가 힘들더라
이렇게 다음페이지에 대한 URL 링크를 제공하며 게시물의 전체 카운트는 9개라는 것을 확인 할 수 있다. 현재 따로 page 파라미터를 지정하지 않아 1페이지를 노출하고 있어서 "previous" 속성엔 null이 들어가 있는 것을 확인할 수 있다.
그리고 우측 상단에는 별도의 페이징 컨포넌트를 제공해준다. 여기서 검색을 적용하게 된다면 어떻게 되는지 확인해보도록 하자.
잘 적용되는 것을 확인할 수 있다. 그리고 쿼리도 정상적으로 잘 적용되서 동작하는 것을 로그를 통해 확인 할 수도 있다.
사실 나는 PageNumberPagination이 적용이 전역설정 외에는 적용이 안되는 줄 알고 있었더랬는데 이번에 포스팅하면서 내장 코드를 분석해보니 위와 같이 코딩을 진행하면 된다는 것을 확인할 수 있었다. 그도 그럴 것이 내장 코드를 확인해보면
이렇게 page_size를 적용받는 부분이 셋팅쪽 속성을 바라보고 있어서였는데 실제로 paginate_queryset을 수행하는 절차를 따라가다보면 PageNumberPagination의 page_size_query_param이라는 속성을 통해 쿼리 파라미터에서 값을 찾고 그 값을 우선해 적용되는 것을 확인 할 수 있었다.(코드가 길어서 따로 확인시켜주긴 어렵다.)
이걸 몰랐던 (사실 API 문서에도 이부분은 설명이 안되어 있었는데... 영알못이라 그냥 모르고 지나쳤을 수도 있지만!) 나는 Restframework를 엄청 욕을 하고 지냈더랬다.
역시 안되는건 없었어. 다음 이시간에 또 만나요 안녕
'Dev > Python' 카테고리의 다른 글
Python(파이썬) 설치하기(For Windows) (0) | 2019.08.08 |
---|---|
Django API 연동하기 - 2. 검색과 페이징 #4 LimitOffsetPagination (0) | 2018.06.13 |
Django API 연동하기 - 2. 검색과 페이징 #2 (2) | 2018.06.06 |
Django API 연동하기 - 2. 검색과 페이징 #1 (0) | 2018.06.05 |
Django API 연동하기 - 1. 준비운동 (0) | 2018.06.01 |