1. 대량 테스트 데이터 만들기 - 장고셸 사용
페이징(Paging) 실습을 위해 먼저 대량의 테이터를 만들 것이다. python manage.py shell 명령어로 장고셸을 실행해고 다음과 같이 한줄씩 입력한다.
이제 장고 셸을 종료하고 로컬 서버를 실행해보면 아래와 300개 이상의 데이터가 한 페이지에 보여진다. 따라서 이러한 문제를 해결하기 위해 페이징(paging) 처리가 반드시 필요하다.
2. views.py - Paginator 클래스 활용
장고에서 페이징을 처리하기 위해선 Paginator 클래스를 사용해야한다. 아래와 같이 Paginator 클래스를 사용하여 index 함수에 페이징 기능을 적용한다.
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Question
from .forms import QuestionForm, AnswerForm
from django.core.paginator import Paginator
def index(request):
# 입력 파라미터
page = request.GET.get('page', '1') # 페이지
# 조회
question_list = Question.objects.order_by('-create_date') #create_date를 역순으로 정렬
# 페이징처리
paginator = Paginator(question_list, 10) # 페이지당 10개씩 보여주기
page_obj = paginator.get_page(page)
context = {'question_list': page_obj}
return render(request, 'notes/question_list.html', context)
#==== 생략 ====
page = request.GET.get('page', '1')은 http://localhost:8000/notes/?page=1 처럼 GET 방식으로 호출된 URL에서 page값을 가져올 때 사용한다. 두번째 인자값은 http:localhost:8000/notes/처럼 page값이 없는 상태로 호출된 경우 디폴트로 1이라는 값을 설정하도록 한 것이다.
그리고 아래 Paginator() 함수의 첫번째 파라미터는 전체 데이터이고, 두번째 파라미터는 페이지당 보여줄 데이터의 개수이다.
page_obj = paginator.get_page(page)는 paginator을 이용하여 요청된 페이지에 해당하는 페이징 객체(page_obj)를 생성한 것이다. 이를 통해 장고가 내부적으로 데이터 전체를 조회하는 것이 아닌 해당 페이지의 데이터만 조회하도록 쿼리를 변경한 것이다.
페이징 객체 속성
page_obj에는 다음과 같은 속성이 있다. 아래 속성들은 템플릿에서 페이징을 처리할 때 사용된다.
항목 | 설명 |
paginator.count | 전체 게시물 개수 |
paginator.per_page | 페이지당 보여줄 게시물 개수 |
paginator.page_range | 페이지 범위 |
number | 현재 페이지 번호 |
previous_page_number | 이전 페이지 번호 |
next_page_number | 다음 페이지 번호 |
has_previous | 이전 페이지 유무 |
has_next | 다음 페이지 유무 |
start_index | 현재 페이지 시작 인덱스(1부터 시작) |
end_index | 현재 페이지의 끝 인덱스(1부터 시작) |
3. 템플릿에 페이징 적용하기
이전에 질문 데이터를 테이블로 출력하는 부분을 구현했었다. 그 부분의 끝 </table>태그 밑에 아래 코드를 추가한다.
<!-- 페이징처리 시작 -->
<ul class="pagination justify-content-center">
<!-- 이전페이지 -->
{% if question_list.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ question_list.previous_page_number }}">이전</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" tabindex="-1" aria-disabled="true" href="#">이전</a>
</li>
{% endif %}
<!-- 페이지리스트 -->
{% for page_number in question_list.paginator.page_range %}
{% if page_number == question_list.number %} #현재 페이지와 같은지 체크
<li class="page-item active" aria-current="page"> #active 클래스: 강조 표시
<a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
</li>
{% endif %}
{% endfor %}
<!-- 다음페이지 -->
{% if question_list.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ question_list.next_page_number }}">다음</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" tabindex="-1" aria-disabled="true" href="#">다음</a>
</li>
{% endif %}
</ul>
<!-- 페이징처리 끝 -->
이전 페이지가 있는 경우에는 "이전" 링크가 활성화되게 하였고, 이전 페이지가 없는 경우 "이전" 링크가 비활성화되도록 하였다. "다음" 페이지의 경우도 마찬가지 방법으로 적용되었다. 그리고 페이지 리스트를 루프 돌면서 해당 페이지로 이동할 수 있는 링크를 생성했다. 이때 현재 페이지와 같을 경우에는 active 클래스를 적용하여 강조표시를 해주었다.
4. 페이지 리스트
3번까지 완료해서 서버를 실행해보면 아래와 같다. 페이징 처리는 잘 되었지만, 페이지가 모구 표시된다는 문제점이 존재한다. 따라서 템플릿에서 이부분을 수정해줄 것이다.
따라서 question_list.html 템플릿을 다음과 같이 수정해준다. "페이지 리스트" 부분을 아래와 같이 수정한다.
{% for page_number in question_list.paginator.page_range %}
{% if page_number >= question_list.number|add:-5 and page_number <= question_list.number|add:5 %}
{% if page_number == question_list.number %}
<li class="page-item active" aria-current="page">
<a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
</li>
{% endif %}
{% endif %}
{% endfor %}
여기서 |add:-5, |add:5 는 템플릿 필터이다. |add:-5는 5만큼 빼라는 의미이고 |add:5는 5만큼 더하라는 의미이다. 위 코드는 페이지 리스트가 현재 페이지 기준으로 좌우 5개씩 보이도록 만든다.
이렇게 페이징 기능을 구현해보았다. 이제 '처음'과 '마지막' 버튼을 구현해보아야겠다.
'Web > Django' 카테고리의 다른 글
장고(Django) 로그인, 로그아웃 페이지 구현하기, django.contrib.auth 활용 (0) | 2021.08.04 |
---|---|
장고(Django) 템플릿 필터 생성 및 적용하기 (0) | 2021.08.04 |
장고(Django) GET과 POST를 활용하여 폼(Form) 작업하기 (0) | 2021.08.03 |
Django(장고) static 디렉터리와 템플릿 상속 및 include 태그 사용 (0) | 2021.08.03 |
Django(장고)에서 POST 방식의 데이터 저장 (0) | 2021.08.03 |