화면에 표시할 레코드가 많은 경우에 페이지마다 나눠서 보여줄 수 있도록 하는 기능을 페이징 또는 페이지네이션이라고 한다. 이번 포스팅에서는 제네릭 뷰에서 제공하는 페이징 기능을 알아보도록 하자.
1. 페이징 기능 활성화하기
- 페이징 기능은 MultipleObjectMixin의 paginate_by 속성을 지정함으로써 활성화 가능하다. ListView와 날짜 기반 제네릭 뷰는 MultipleObjectMixin을 상속받고 있기 때문에 페이징이 가능한 것이다.
- 장고의 페이징 기능이 활성화되면 객체 리스트에는 페이지별로 구분되어 저장된다. 즉, 디폴트 context 변수인 object_list에는 특정 페이지에 해당하는 객체만 담긴다.
- paginate_by 속성에는 페이지당 몇 개의 항목을 출력할지 정수로 지정한다.
2. 페이지 번호 지정
아래에 소개된 2가지 방법 중에서 하나를 선택하면 된다.
1) URL의 요청 파라미터 page로 전달
?page=3
2) URLconf의 <int:page>를 통해 page 파라미터를 전달
path('posts/page<int:page>/', PostLV.as_view()),
참고로, 파라미터의 이름을 page가 아닌 다른 것으로 쓰려면 뷰의 page_kwargs 속성으로 알려줘야 한다.
3. 템플릿 파일에서 사용되는 context 변수
- object_list : 특정 페이지에 해당되는 객체들만 담겨있음
- is_paginated : 페이징 적용 여부
- paginator : django.core.paginator.Paginator 클래스의 객체 ([4. Paginator] 참고)
- page_obj : django.core.paginator.Page 클래스의 객체 ([5. Page] 참고)
※ 페이징 처리가 안되는 경우에는 paginator, page_obj 값은 None을 가지게 된다.
4. Paginator
- 전체 페이지를 담당하며, 특정 페이지 객체인 django.core.paginator.Page 객체를 생성한다.
1) 인자
class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True)
- object_list : 페이징 대상인 전체 객체 리스트다. 리스트, 튜플, QuerySet 타입이 올 수 있다.
- per_page : 페이지당 최대 항목 수
- orphans : 마지막 페이지에 넣을 수 있는 항목의 최소 개수로, 디폴트 값은 0이다. 마지막 페이지의 항목 개수가 orphans 값보다 작다면 per_page 값과 상관없이 그 이전 페이지에 강제로 포함시킨다.
- allow_empty_first_page : 첫 페이지의 항목 개수가 0임을 허용하는지의 여부다. False 값을 가진다면 첫 페이지의 항목 개수가 0일 때 EmptyPage 에러가 발생한다.
2) 메소드
- page(n) : n번째 페이지에 대한 Page 객체를 반환한다. n은 1부터 시작하며, 해당 페이지가 존재하지 않으면 InvaildPage 에러가 발생한다.
- get_page(n) : n번째 페이지에 대한 Page 객체를 반환한다. n은 1부터 시작하며, 인자가 음수이거나 최대 페이지 숫자보다 크면 마지막 페이지로 처리되고, 인자가 숫자가 아니면 첫 페이지로 처리된다.
3) 속성
- count : 항목의 총 개수
- num_pages : 페이지의 총 개수
- page_range : 1부터 시작하는 페이지의 범위 리스트
5. Page
- Paginator 객체에 의해 생성되는 특정 페이지에 대한 객체다.
1) 인자
class Page(object_list, number, paginator)
- object_list : Paginator의 object_list와 동일함
- number : 몇 번째 페이지인지를 나타냄
- paginator : Page를 생성해주는 Paginator 객체
2) 메소드
- has_next() : 다음 페이지의 존재 여부
- has_previous() : 이전 페이지의 존재 여부
- has_other_pages() : 다음 페이지 또는 이전 페이지의 존재 여부
- next_page_number() : 다음 페이지 번호 (다음 페이지가 유효하지 않다면 InvalidPage 에러 발생)
- previous_page_number() : 이전 페이지 번호 (이전 페이지가 유효하지 않다면 InvalidPage 에러 발생)
- start_index() : 현재 페이지 첫 번째 항목의 전체 기준 인덱스를 반환 (1부터 시작)
- end_index() : 현재 페이지 마지막 항목의 전체 기준 인덱스를 반환 (1부터 시작)
3) 속성
- object_list : 현재 페이지에 대한 객체 리스트
- number : 1부터 시작하는 현재 페이지의 번호
- paginator : 현재 Page를 생성해준 Paginator 객체
6. 템플릿 코드에 적용
현재 페이지를 표시하거나 페이지를 바꾸기 위한 nav는 다음과 같이 작성할 수 있다. page라는 요청 파라미터를 통해 페이지 전환이 이루어지도록 <a>의 href를 지정했다. 그리고 첫 페이지면 Previous 버튼을 비활성화했고, 마지막 페이지면 Next 버튼을 비활성화했다.
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item">
<a href="?page={{ page_obj.previous_page_number }}" class="page-link">Previous</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">Previous</a>
</li>
{% endif %}
<li class="ms-3 me-3 mt-1"><span class="align-middle">Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span></li>
{% if page_obj.has_next %}
<li class="page-item">
<a href="?page={{ page_obj.next_page_number }}" class="page-link">Next</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link">Next</a>
</li>
{% endif %}
</ul>
</nav>
화면 출력 내용은 다음과 유사하게 나올 것이다.
'Django' 카테고리의 다른 글
[Django] Form 처리 방식 정리 (0) | 2023.02.16 |
---|---|
[Django] 단축 함수 (0) | 2023.02.15 |
[Django] QuerySet에서 사용하는 '__'의 의미 (0) | 2023.02.13 |
[Django] 공통 context 변수 설정하기 (0) | 2023.02.11 |
[Django] 날짜형 클래스형 뷰에서 404 에러가 발생하는 경우 (0) | 2023.02.11 |
댓글