Django
16. 게시판 페이징 기능 구현하기
테니드2
2021. 4. 15. 11:30
- 게시판 임시 데이터 만들기
#파이썬 쉘 진입 및 라이브러리 추가
>python manage.py shell
# 파이썬 쉘 진입
>>> from pybo.models import Question
>>> from django.utils import timezone
#반복문을 이용하여 데이터 삽입
>>> for i in range(300):
... q = Question(subject='테스트 데이터:[%03d]' % i, content='컨텐츠 내용', create_date=timezone.now())
... q.save()
...
>>>
# ListView를 이용한 간단한 페이징 구현 (project/main/views.py)
class index(ListView):
model = Question
# 템플릿 파일 지정
template_name = 'main/index.html'
# 화면에 표시될 데이터의 개수
paginate_by = 10
# 추가로 보낼 데이터
def get_context_data(self, **kwargs):
context = super(index, self).get_context_data()
context['page_title'] = '질문과 답변'
return context
# request를 받으면 실행되는 Query
def get_queryset(self):
return self.model.objects.order_by('-create_date')
❖ paginate_by = 한 페이지에 보여질 데이터 개수 로 값을 설정하면 한 페이지에 대한 데이터들은 기본적으로 page_obj라는 변수에 들어가게 된다.
# 템플릿 구현 (project/main/templates/index.html)
{% extends 'base.html' %}
{% load custom_filter %}
{% block page_title %} {{ page_title }} {% endblock %}
{% block content %}
<div class="container my=3">
<table class="table">
<thead>
<tr class="thead-dark">
<th>번호</th>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
{% if page_obj %}
{% for question in page_obj %}
<tr>
<td>{{ paginator.count }}</td>
<td>
<a href="{% url 'main:detail' question.id %}">{{ question.subject }}</a>
{% if question.answer_set.count > 0 %}
<span class="text-danger small ml-2">{{ question.answer_set.count }} </span>
{% endif %}
</td>
<td>{{ question.create_date }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="3">질문이 없습니다.</td>
</tr>
{% endif %}
</tbody>
</table>
<!-- page nav -->
<ul class="pagination justify-content-center">
<!-- 이전 페이지-->
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.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 paginator.page_range %}
{% if page_number == page_obj.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 page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.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 'main:question_create' %}" class="btn btn-primary">질문 등록</a>
</div>
{% endblock %} #}
- 결과 화면

☑︎ 문제점
• 1. 각 페이지 번호가 1~10로 고정 되어 있는 점
• 2. 페이지 번호가 너무 많아져 정상적으로 표기가 안되는 점
# 사용자 지정 템플릿 필터 만들기 (sub: 빼기 연산을 위한 필터)
1. 템플릿 필터 폴더 만들기: 템플릿 폴더와 같은 위치에 templatetags 폴더 생성
2. filter.py 생성
from django import template
register = template.Library()
@register.filter
def sub(value, arg):
return value - arg
3. 적용할 템플릿 상단에 {% load 'filter 파일명' %} 작성
{% extends 'base.html' %}
{% load custom_filter %}
{% block page_title %} {{ page_title }} {% endblock %}
{% block content %}
<div class="container my=3">
<table class="table">
<thead>
<tr class="thead-dark">
<th>번호</th>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
{% if page_obj %}
{% for question in page_obj %}
<tr>
<!-- 1. 문제점 해결책 각 페이지 번호 -->
<!-- 번호 = 전체 건수 - 시작인덱스 - 현재인덱스 +1 -->
<td>{{ paginator.count | sub:page_obj.start_index|sub:forloop.counter0|add:1 }}</td>
<td>
<a href="{% url 'main:detail' question.id %}">{{ question.subject }}</a>
{% if question.answer_set.count > 0 %}
<span class="text-danger small ml-2">{{ question.answer_set.count }} </span>
{% endif %}
</td>
<td>{{ question.create_date }}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="3">질문이 없습니다.</td>
</tr>
{% endif %}
</tbody>
</table>
<!-- page nav -->
<ul class="pagination justify-content-center">
<!-- 이전 페이지-->
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.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 paginator.page_range %}
<!-- 2. 문제점 해결 페이지 버튼 수 조정 -->
<!-- 페이지 수 조정 -->
{% if page_number >= page_obj.number|add:-5 and page_number <= page_obj.number|add:5 %}
{% if page_number == page_obj.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 %}
<!-- 다음 페이지 -->
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.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 'main:question_create' %}" class="btn btn-primary">질문 등록</a>
</div>
{% endblock %} #}
- 결과 화면

출처: wikidocs.net/book/4223 (점프 투 장고)