본문 바로가기

[Python] django 게시판 페이징 처리

액트 2022. 10. 11.
반응형

페이징이란 게시판 등과 같은 글의 목록 등을 구간 별로 나누어 페이지 형태로 보여주는 작업을 말하는 것입니다.

게시판의 페이징 처리가 안되어 있으면 있는 모든 게시물이 한 페이지에 출력되어 스크롤바가 엄청 길어지는 현상이 나타납니다.

지금까지 구현한 질문 목록은 현재 페이징 처리가 안되어 있기 때문에 게시물 300개를 작성하면 한 페이지에 300개의 게시물이 모두 표시됩니다.

확인을 위해 실제로 대량의 데이터를 만들어 보겠습니다.

다음처럼 명령프롬프트(cmd) 창에서 장고 셸을 실행합니다.

>python manage.py shell

질문 데이터를 생성하기 위한 모듈을 임포트 합니다.

>>>from pybo.models import Question
>>>from django.utils import timezone

그리고 다음과 같이 300개의 테스트 데이터를 생성합니다.

>>> for i in range(300):
...		q = Question(subject='테스트 데이터:[%03d]' % i, content='내용무', create_Date=timezone.now())
...		q.save()
...
>>>

q.save() 까지 입력하시고 Enter 키 누르시고 ... 옆에 아무것도 없는 곳에서 Enter 키를 한번 더 누르면 명령문이 실행됩니다.

300개의 데이터가 처리되는데 약 1초 정도 소요되니 기다리시면 >>> 가 나오면서 명령어 처리가 끝이납니다.

이제 http://localhost:8000/pybo 페이지를 확인하시면 아래와 같이 데이터를 확인하실 수 있습니다.

300개의 데이터가 한 화면에 전부 보여지는 것을 확인하실 수 있습니다. 이제 페이징 처리를 하여 페이지에 번호를 매겨 깔끔하게 정리해 보겠습니다.

 

페이징 처리

장고에서는 페이징 처리를 위한 Paginator 클래스를 제공합니다.

데이터 처리를 위한 views.py 을 다음과 같이 수정합니다.

mysite\pybo\views.py

from django.utils import timezone
from .forms import QuestionForm
from django.core.paginator import Paginator     #(추가)

def index(request):
    page = request.GET.get('page', '1') #페이지 (추가)
    question_list = Question.objects.order_by('-create_date')
    paginator = Paginator(question_list, 10) #페이지당 10개씩 보여주기 (추가)
    page_obj =- paginator.get_page(page) #(추가)
    context = {'question_list': page_obj}	#(수정)
    return render(request, 'pybo/question_list.html', context)
from django.core.paginator

Paginator 사용을 위해 import 해 주었다.

page = request.GET.get('page', '1')

http://localhost:8000/pybo/?page=1 처럼 GET 방식으로 호출된 URL에서 page 값을 가져올 때 사용합니다.

만약 http://localhost:8000/pybo 처럼 page 값 없이 호출된 경우에는 디폴트로 1이라는 값을 설정합니다.

그리고 Paginator 클래스를 다음처럼 사용합니다.

paginator = Paginator(question_list, 10)

첫 번째 파라미터 question_list는 게시물 전체를 의미하는 데이터이고 

두 번째 파라미터 10은 페이지당 보여줄 게시물의 개수입니다.

page_obj = paginator.get_page(page)

그리고 paginator를 이용하여 요청된 페이지(page)에 해당되는 페이징 객체(page_obj)를 생성합니다.

이렇게 하면 장고 내부적으로는 데이터 전체를 조회하지 않고 해당 페이지의 데이터만 조회하도록 쿼리가 변경됩니다.

위와 같이 설정하시고 http://localhost:8000/pybo 페이지를 새로고침하시면 아래와 같이 10개의 데이터만 조회된 것을 확인하실 수 있고 아직 페이지를 나타내는 숫자는 안보이는 것을 확인하실 수 있습니다.

페이징 객체 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부터 시작)

 

템플릿에 페이징 적용하기

데이터 변경은 끝났으니 이제 화면에 보이는 템플릿을 수정할 차례입니다.

페이지 숫자 처리를 위해 아래와 같이 코드를 수정하십시오.

mysite\templates\pybo\question_list.html

</table> 태그 아래에 입력하시면 됩니다.

(... 생략 ...)
    </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|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 %}
        {% 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>
    <!-- 페이징처리 끝 -->
    <a href="{% url 'pybo:question_create' %}" class="btn btn-primary">질문 등록하기</a>
</div>
{% endblock %}

이전 페이지가 있는 경우 "이전" 링크에 활성화되게 하였습니다.

이전 페이지가 없는 경우 "이전" 링크가 비활성화 되도록 하였습니다.

다음 페이지도 마찬가지 입니다.

그리고 페이지 리스트를 루프 돌면서 해당 페이지로 이동할 수 있는 링크를 생성하였습니다.

현재 페이지와 같을 경우에는 active클래스를 적용하여 강조 표시도 해주었습니다.

{% if page_number >= question_list.number|add:-5 and page_number <= question_list.number|add:5 %}

위 코드는 페이지 리스트가 현재 페이지 기준으로 좌우 5개씩 보이도록 만드는 것입니다.

현재 페이지를 의미하는 question_list.number 보다 5만큼 크거나 작은 값만 표시되도록 만든 것입니다.

즉 위 아래로 5개의 페이지만 노출되는 것입니다.

예를 들어, 현재 페이지가 6이라면 아래 사진과 같이 1~11까지 표시될 것입니다.

본 글은 점프투장고 위키독스를 보고 공부하고 정리한 내용입니다. 자세한 사항은 점프투장고를 참고해 주세요.!^^

반응형

댓글