[17. Django] Paging_exam (250710 수업)

해피해피슈크림·2025년 7월 10일

1. 페이징 처리

페이징 처리

  • 대량의 데이터를 여러 페이지로 나눠서 출력하는 것.
  • Django에서는 Paginator와 Page 클래스를 통해 처리한다.

Paginator 클래스

  • 전체 페이징 처리를 관리하는 클래스
  • 전체 데이터관련 정보, 각 페이지당 보여줄 데이터의 정보 등을 제공

Page 클래스

  • 한페이지에대한 데이터를 관리
  • Paginator를 통해서 생성.
    • Pagenator객체.page(페이지 번호)
  • iterable 타입. 페이지에 속한 데이터들을 제공
  • Page객체.object_list 속성: 페이지가 가진 데이터들을 List로 반환

이전/다음 페이지가 있는지

  • Page객체.has_previous() / Page객체.has_next()
  • 1페이지: 이전페이지? X, 다음페이지? O
  • 중간 페이지: 이전페이지? O, 다음페이지? O
  • 마지막 페이지: 이전? O, 다음페이지? X

이전/다음페이지 번호 조회

  • Page객체.number: 현재 페이지 번호
  • Page객체.previous_page_number(): 이전페이지 번호 조회
  • page객체.next_page_number(): 다음페이지 번호 조회

Question, Choice Dummy 데이터 추가


list_paging 함수 추가

먼저 기존 list 함수를 list_no_paging으로 변경한다.

views.py

# views.py
def list_no_paging(request): # 함수 이름 변경: list -> list_no_paging
    # DB에서 question들을 조회
    q_list = Question.objects.all().order_by("-pub_date") # 내림차순 -> 최신 질문 목록

    # render(): template을 실행해서 그 결과로 HttpResponse를 반환하는 함수.
    return render(
        request,    # HttpRequest 객체 
        "polls/list.html",  # Template 파일의 경로
        {"question_list": q_list} # Template에게 전달할 값 -> context value: dictionary
    )    
# views.py
from django.core.paginator import Paginator

###########################
# list -> paging 처리 목록 View
# - 요청파라미터(querystring)으로 page 번호를 받는다. (=get 방식)
# - 응답 context value(data)
#   - 현재 page에 보여줄 데이터들
#   - 현재 페이지가 속한 페이지 그룹의 시작/끝 페이지 번호
#   - 현재 페이지 그룹의 시작 페이지가 **이전페이지가 있는지 여부/이전 페이지 번호**
#   - 현재 페이지 그룹의 끝 페이지가 **다음페이지가 있는지 여부/다음 페이지 번호**
def list(request):
    pagenate_by = 10        # 한 페이지당 데이터 개수
    page_group_count = 10   # 한 페이지 그룹당 페이지 수
    # http://ip:port/polls/list?page=15 -> 15를 받아서 int로 바꿈
    # http://ip:port/polls/list -> 받은 번호가 없다면 기본값 1을 반환
    current_page = int(request.GET.get('page', 1))  # 현재 조회하려는 페이지 번호, default=1
                                                    # 기본적으로 문자열 형태로 반환 -> int로 변환.

    # Question 데이터 조회 + Pagenator 객체 생성
    question_list = Question.objects.all().order_by("-pk") 
    pn = Paginator(question_list, pagenate_by)

    # 현재 페이지가 속한 페이지 그룹의 start/end 페이지 번호 조회
    start_index = int((current_page-1)/page_group_count) * page_group_count
    end_index = start_index + page_group_count
    page_range = pn.page_range[start_index:end_index]

    # context_value(context_data) -> template에 전달할 값들. dictionary
    context_value = {
        "page_range": page_range,    # Page group의 시작/끝페이지 range
        "question_list": pn.page(current_page)   # 페이지의 데이터들
    }

    # 페이지 그룹의 시작 페이지가 이전 페이지가 있는지, 이전 페이지 번호는 무엇인지
    start_page = pn.page(page_range[0])
    has_previous = start_page.has_previous()
    if has_previous:
        previous_page = start_page.previous_page_number()
        context_value['has_previous'] = has_previous
        context_value['previous_page'] = previous_page

    # 페이지 그룹의 끝 페이지가 다음 페이지가 있는지, 다음 페이지 번호는 무엇인지
    end_page = pn.page(page_range[-1])
    has_next = end_page.has_next()
    if has_next:
        next_page = end_page.next_page_number()
        context_value['has_next'] = has_next
        context_value['next_page'] = next_page
    
    return render(request, "polls/list.html", context_value)

list.html 수정 (1) - 질문 목록 디자인 변경

<!-- polls/templates/polls/list.html -->
 {%extends "layouts/main_layout.html"%} 

 {%block title%}설문 목록{%endblock title%}

 {%block contents%}
    <h1>설문 목록</h1>
    <div class="list-group"> <!-- ⭐ div 그룹으로 묶어줌 -->
        {% for question in question_list %} <!-- for문 시작 -->
        <!-- <a href="/polls/vote_form/{{question.pk}}"> -->
        <!-- ⭐ a 태그에 클래스 추가 -->
        <a href="{% url 'polls:vote_form' question.pk %}" class="list-group-item list-group-item-action">
        {{question.pk}}. {{question.question_text|truncatewords:4}}<br>
        </a>
        {% empty %}
        <b>등록된 설문이 없습니다.</b>
        {% endfor %} <!-- for문 끝 -->
    </div>
    
{%endblock contents%}


질문 항목 위에 마우스를 대면 색이 변한다. (class - action)

list.html 수정 (2) - 이전, 다음 페이지 넘어가는 버튼 만들기

<!-- polls/templates/polls/list.html -->
 {%extends "layouts/main_layout.html"%} 

 {%block title%}설문 목록{%endblock title%}

 {%block contents%}
    <h1>설문 목록</h1>
    <div class="list-group">
        {% for question in question_list %} <!-- for문 시작 -->
        <!-- <a href="/polls/vote_form/{{question.pk}}"> -->
        <a href="{% url 'polls:vote_form' question.pk %}" class="list-group-item list-group-item-action">
        {{question.pk}}. {{question.question_text|truncatewords:4}}<br>
        </a>
        {% empty %}
        <b>등록된 설문이 없습니다.</b>
        {% endfor %} <!-- for문 끝 -->
    </div>
    <!-- paging 처리 -> 이동할 페이지 링크 추가 -->
    <ul>
        {# 이전 페이지 그룹 이동 버튼 #}
        {% if has_previous %}
            <li>
                <a href="{% url 'polls:list' %}?page={{previous_page}}">
                    이전
                </a>
            </li>
        {% else %}
            <li>
                <span>⬅️ 이전</span>
            </li>
        {% endif %}

        {# 이동할 페이지 번호, 링크 #}

        {# 다음 페이지 그룹 이동 버튼 #}
        {% if has_next %}
            <li>
                <a href="{% url 'polls:list' %}?page={{next_page}}"> 
                    다음
                </a>
            </li>
        {% else %}
            <li>
                <span>다음 ➡️</span>
            </li>
        {% endif %}
    </ul>
 {%endblock contents%}


넘어갈 페이지가 있으면 a 태그, 없으면 스판 태그(화살표 있는 거)가 뜬다.

list.html 수정 (3) 최종!

업로드중..

<!-- polls/templates/polls/list.html -->
 {%extends "layouts/main_layout.html"%} 

 {%block title%}설문 목록{%endblock title%}

 {%block contents%}
    <h1>설문 목록</h1>
    <div class="list-group">
        {% for question in question_list %} <!-- for문 시작 -->
        <!-- <a href="/polls/vote_form/{{question.pk}}"> -->
        <a href="{% url 'polls:vote_form' question.pk %}" class="list-group-item list-group-item-action">
        {{question.pk}}. {{question.question_text|truncatewords:4}}<br>
        </a>
        {% empty %}
        <b>등록된 설문이 없습니다.</b>
        {% endfor %} <!-- for문 끝 -->
    </div>
    <!-- paging 처리 -> 이동할 페이지 링크 추가 -->
    <ul class="pagination mt-3">
        {# 이전 페이지 그룹 이동 버튼 #}
        {% if has_previous %}
            <li class="page-item">
                <a href="{% url 'polls:list' %}?page={{previous_page}}" class="page-link">
                    이전
                </a>
            </li>
        {% else %}
            <li class="page-item">
                <span class="page-link disabled">⬅️ 이전</span>
            </li>
        {% endif %}

        {# 이동할 페이지 번호, 링크 - 현재 페이지는 링크를 걸지 않는다. #}
        {% for page_no in page_range %}
            {% if page_no == question_list.number %}
                <li class="page-item">
                    <span class="page-link disabled">{{page_no}}</span>
                </li>
            {% else %}
                <li class="page-item">
                    <a href="{% url 'polls:list' %}?page={{page_no}}" class="page-link">
                        {{page_no}}
                    </a>

                </li>
            {% endif %}
        {% endfor %}

        {# 다음 페이지 그룹 이동 버튼 #}
        {% if has_next %}
            <li class="page-item">
                <a href="{% url 'polls:list' %}?page={{next_page}}" class="page-link"> 
                    다음
                </a>
            </li>
        {% else %}
            <li class="page-item">
                <span class="page-link disabled">다음 ➡️</span>
            </li>
        {% endif %}
    </ul>
 {%endblock contents%}

⭐ 문법 체크: 중괄호 한 개? 두 개? ({% if %}와 {% else %} 문법 오류)

문제

{{% if page_no == question_list.number %}}

틀린 문법입니다.

💡 Django 템플릿에서 if문은 {% if ... %}로 써야 하고, 중괄호 두 개({{ }})는 변수 출력에만 씁니다.

해결 방법

{% if page_no == question_list.number %}

0개의 댓글