페이지 네이션

Ethan·2024년 1월 18일
0

Dear

목록 보기
6/13

페이지 네이션을 만드는 방법을 알아본다.


1. views 수정

먼저 뷰를 수정해야 한다.


1.1 모듈 불러오기

장고의 페이지네이터를 불러온다.

#views.py

from django.core.paginator import Paginator

1.2 post_list 수정하기

post_list 함수를 수정한다.

views.py > post_list


def post_list(request):
    posts = Post.objects.all().order_by("-dt_modified")
    page = request.GET.get("page", 1)
    paginator = Paginator(posts, 9)
    page_obj = paginator.get_page(page)
    context = {"page_obj": page_obj}
    return render(request, 'posts/post_list.html', context=context)

요청으로부터 page 파라미터에 인자를 넘겨받아 변수 page에 지정한다. 만약 넘겨받은 인자가 없다면 1로 간주한다.

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

변수 posts의 데이터를 한 페이지 당 9개로 구분하고 변수 paginator에 지정한다.

    paginator = Paginator(posts, 9)

변수 paginator 를 통해 전체 데이터를 전체 데이터를 한 페이지 당 N개의 데이터로 나누고 변수 page와 일치하는 페이지 번호의 데이터들을 불러온 뒤 변수 page_obj에 지정한다.

    page_obj = paginator.get_page(page)

풀어서 설명하자면 아래와 같다.
page_obj
1. paginator를 통해 전체 데이터를 한 페이지 당 9개의 데이터로 구분 한 뒤,
2. 템플릿으로부터 파라미터로 전달받은 page의 값이 2라면,
3. 2페이지에 포함된 10번부터 18번까지의 데이터들을 호출한다.

context로 page_ojb를 넘겨준다.

    context = {"page_obj": page_obj}

요청과 context를 전달하면서 템플릿을 렌더한다.

    return render(request, 'posts/post_list.html', context=context)

1.3 템플릿 수정

우선 데이터를 호출하는 코드 중 기존 context로 넘겨받던 postspage_obj 로 변경했기 때문에 해당 부분을 변경해준다.

그런데 for 문에서 page_obj만 단독으로 사용하면 전체 게시글 개수, 전체 페이지 수, 이전 페이지 및 다음 페이지 존재 등은 확인할 수 있지만 데이터에는 접근할 수 없다. 따라서 페이지 내에 있는 데이터에 접근하기 위해서는 .object_list를 붙여줘야 한다.

<!--post_list.html-->

    <div class="btn_post">
        <a href={% url "post-create" %}>기록하기</a>
    </div>
    {% if page_obj %}
        <div class="post_container">
            {% for post in page_obj.object_list %}
                <div class="post"><a href="{% url "post-detail" post.id %}">
                    <h2 class="title">{{post.title}}</h2>
                    <p class="date">{{post.dt_created}}</p>
                    <p class="text">{{post.content}}</p>
                </a></div>
            {% endfor %}
        </div>

1.3.1 페이지네이션 코드

이후 페이지네이션을 표기하는 코드를 작성한다.

<!--post_list.html-->

        <div class="pagination">
            {% if page_obj.has_previous %}
                <a class="able" href="?page=1">&lt&lt</a>
            {% else %}
                <a class="disable" onclick="return false;" href="#">&lt&lt</a>
            {% endif %}

            {% if page_obj.has_previous %}
                <a class="able" href="?page={{ page_obj.previous_page_number }}">&lt</a>
            {% else %}
                <a class="disable" onclick="return false;" href="#">&lt</a>
            {% endif %}


            {% for page_number in page_obj.paginator.page_range %}
                {% if page_number == page_obj.number %}
                    <a class="disable" id="current" onclick="return false;" href="#">{{ page_number }}</a>
                {% elif page_obj.number <= 3 and page_number <= 5 %}
                    <a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
                {% elif page_obj.number > page_obj.paginator.num_pages|add:-3 and page_number >= page_obj.paginator.num_pages|add:-4 %}
                    <a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
                {% elif page_number >= page_obj.number|add:-2 and page_number <= page_obj.number|add:2 %}
                    <a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
                {% endif %}
            {% endfor %}
        
            
            {% if page_obj.has_next %}
            <a class="able" href="?page={{ page_obj.next_page_number }}">&gt</a>
            {% else %}
            <a class="disable" onclick="return false;" href="#">&gt</a>
            {% endif %}
            
            {% if page_obj.has_next %}
            <a class="able" href="?page={{ page_obj.paginator.num_pages }}">&gt&gt</a>
            {% else %}
            <a class="disable" onclick="return false;" href="#">&gt&gt</a>
            {% endif %}
        </div>

무척 어려워 보이지만 전체적인 맥락을 파악하면 이해할 수 있다.

우리가 페이지네이션에서 만들어야할 것은 아래와 같다.

  1. 처음으로
  2. 이전으로
  3. 현재 페이지 기준 근접한 페이지
  4. 다음으로
  5. 마지막으로

1.3.2 처음, 이전, 다음, 마지막 버튼

먼저 처음으로이전으로를 살펴본다.

{% if page_obj.has_previous %}
	<a class="able" href="?page=1">&lt&lt</a>
{% else %}
	<a class="disable" onclick="return false;" href="#">&lt&lt</a>
{% endif %}

{% if page_obj.has_previous %}
	<a class="able" href="?page={{ page_obj.previous_page_number }}">&lt</a>
{% else %}
	<a class="disable" onclick="return false;" href="#">&lt</a>
{% endif %}

처음으로 버튼은 if문을 사용해
1. 이전 페이지가 있다면 page 파라미터1을 인자로 전달하는 <a> 태그를 생성
2. 이전 페이지가 없다면 클릭해도 반응이 없는 <a> 태그를 생성한다.

이전으로 버튼은 if문을 사용해
1. 이전 페이지가 있다면 page 파라미터이전 페이지의 page 번호를 인자로 전달하는 <a> 태그를 생성
2. 이전 페이지가 없다면 클릭해도 반응이 없는 <a>태그를 생성한다.

다음으로마지막으로 버튼을 이와 비슷하니 따로 설명하지 않겠다.


1.3.3 현재 페이지 기준 근접한 페이지

이 부분은 page_obj에 사용된 paginator를 통해 페이지의 전체 범위를 반복해 page_number를 찾는다.

{% for page_number in page_obj.paginator.page_range %}
    {% if page_number == page_obj.number %}
        <a class="disable" id="current" onclick="return false;" href="#">{{ page_number }}</a>
    {% elif page_obj.number <= 3 and page_number <= 5 %}
        <a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
    {% elif page_obj.number > page_obj.paginator.num_pages|add:-3 and page_number >= page_obj.paginator.num_pages|add:-4 %}
        <a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
    {% elif page_number >= page_obj.number|add:-2 and page_number <= page_obj.number|add:2 %}
        <a class="able" href="?page={{ page_number }}">{{ page_number }}</a>
    {% endif %}
{% endfor %}

첫번 째 if문은 현재 반복중인 페이지가 현재 페이지와 일치하면 클릭해도 반응없는 <a> 태그를 생성하기 위함이다.

나머지 elif문은 현재 페이지에 따라서 총 5개의 인접한 페이지만 호출되도록 제한하는 내용이다.

그 외 중앙정렬, 폰트, 호버 등 간단한 css를 적용하기 위해 <a>태그별로 클래스를 지정했다.
업로드중..


페이지네이션은 직접 완벽하게 만들기에는 많이 복잡하다. 웬만하면 남이 작성한 코드를 사용하자.

profile
글로 쓰면 머리 속에 정리가 되...나?

0개의 댓글

관련 채용 정보