Web/Django

Django - 페이징

괘창 2024. 5. 27. 21:55

● 페이징

페이징을 구현하기 전에 페이징을 테스트할 수 있을 정도로 충분한 데이터 생성이 필요하다.
대량의 테스트 데이터를 만드는 가장 좋은 방법은 장고셸을 이용하면 된다.

 

- 테스트 데이터 대량 상성

* 장고 셸 실행
(mysite) c:\projects\mysite>python manage.py shell
>>> from pybo.models import Question
>>> from django.utils import timezone

- 100개 데이터 생성
>>> for i in range(100):
...     q = Question(subject='test data:[%03d]' % i, content='내용무', create_date=timezone.now())
...     q.save() #엔터필수
...
>>>  exit()

**

[%03d]

% : 문자열 포맷팅 연산자

0 : 해당 숫자를 0으로 채우라는 의미

3 : 최소한의 자리수이며, 위 내용은 세자리로 표시됨을 의미

ㄴ 숫자가 세자리 미만이면 앞에 0으로 채워진다.

d : 십진수 정수를 의미

 

** 

100개의 데이터가 한 페이지에 생성된 것을 확인할 수 있다.


● Paginator

페이징을 위해 사용하는 클래스

[파일명: projects\mysite\pybo\views.py]
(.. 생략 ..)
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')
    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)

(.. 생략 ..)

**

page = request.GET.get('page', '1')은 http://localhost:8000/pybo/?page=1 처럼

GET 방식으로 호출된 URL에서 page값을 가져올 때 사용한다.

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

 

paginator를 이용하여 요청된 페이지(page)에 해당되는 페이징 객체(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부터 시작)
이 속성들은 템플릿에서 페이징을 처리할 때 사용된다.

- 템플릿에 페이지 적용

[파일명: projects\mysite\templates\pybo\question_list.html]
(.. 생략 ..)
    </table>
    <!-- pagin 처리 -->
    <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">
            <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 %}

 

※ 템플릿에 사용된 주요 페이징 기능 표

페이징 기능 코드
이전 페이지가 있는지 체크 {% if question_list.has_previous %}
이전 페이지 번호 {{ question_list.previous_page_number }}
다음 페이지가 있는지 체크 {% if question_list.has_next %}
다음 페이지 번호 {{ question_list.next_page_number }}
페이지 리스트 루프 {% for page_number in question_list.paginator.page_range %}
현재 페이지와 같은지 체크 {% if page_number == question_list.number %}

**

pagination, page-item, page-link 등이 부트스트랩 pagination 컴포넌트의 클래스
부트스트랩 pagination - https://getbootstrap.com/docs/5.1/components/pagination/

 

Pagination

Documentation and examples for showing pagination to indicate a series of related content exists across multiple pages.

getbootstrap.com


- 페이지 리스트

[파일명: projects\mysite\templates\pybo\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개씩 보이도록 만든다.

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