점프 투 장고 추가 기능(답변 페이징과 정렬)
답변 페이징과 정렬
점프 투 장고의 첫 번째 숙제 답변 페이징과 정렬 기능을 구현해봅시다.
새로운 url 경로나 함수를 작성하지 않고 기존의 코드를 수정하여 구현하는 것이 목표입니다.
먼저 답변 리스트 페이징은 질문 리스트 페이징과 동일하게 작성을 했습니다.
question_datail.html
<!-- 페이징처리 시작 -->
<ul class="pagination justify-content-center">
<!-- 처음페이지 -->
{% if answer_list.has_previous %}
<li class="page-item">
<a class="page-link" href="?page=1">처음</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" tabindex="-1" aria-disabled="true" href="#">처음</a>
</li>
{% endif %}
<!-- 이전페이지 -->
{% if answer_list.has_previous %}
<li class="page-item">
<a class="page-link" data-page="{{ answer_list.previous_page_number }}"
href="javascript:void(0)">이전</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 answer_list.paginator.page_range %}
{% if page_number >= answer_list.number|add:-5 and page_number <= answer_list.number|add:5 %}
{% if page_number == answer_list.number %}
<li class="page-item active" aria-current="page">
<a class="page-link" data-page="{{ page_number }}"
href="javascript:void(0)">{{ page_number }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" data-page="{{ page_number }}"
href="javascript:void(0)">{{ page_number }}</a>
</li>
{% endif %}
{% endif %}
{% endfor %}
<!-- 다음페이지 -->
{% if answer_list.has_next %}
<li class="page-item">
<a class="page-link" data-page="{{ answer_list.next_page_number }}"
href="javascript:void(0)">다음</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" tabindex="-1" aria-disabled="true" href="#">다음</a>
</li>
{% endif %}
<!-- 끝페이지 -->
{% if answer_list.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ answer_list.paginator.num_pages }}">마지막</a>
</li>
{% else %}
<li class="page-item disabled">
<a class="page-link" tabindex="-1" aria-disabled="true" href="#">마지막</a>
</li>
{% endif %}
</ul>
<!-- 페이징처리 끝 -->
<form id="searchForm" method="get" action="{% url 'pybo:detail' question.id %}">
<input type="hidden" id="page" name="page" value="{{ page }}">
</form>
<script type='text/javascript'>
const page_elements = document.getElementsByClassName("page-link");
Array.from(page_elements).forEach(function(element){
element.addEventListener('click', function(){
document.getElementById('page').value = this.dataset.page;
document.getElementById('searchForm').submit();
});
});
</script>
댓글 페이지 번호를 누르면 JavaScript 코드가 현재 페이지 번호를 searchForm에 전달하고, searchForm은 해당 URL로 이동하여 페이지네이션을 수행한 후 화면을 렌더링합니다. 페이지네이션을 수행하는 코드는 아래에 있습니다.
base_views.py
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
answer_list = Answer.objects.filter(question=question).order_by('-create_date')
page = request.GET.get('page', '1')
paginator = Paginator(answer_list, 1)
answer_obj = paginator.get_page(page)
context = {'question': question, 'answer_list': answer_obj}
return render(request, 'pybo/question_detail.html', context)
answer_list를 생성해 정렬된 답변들을 저장하고, page에서 현재 페이지 값을 가져와 페이징을 진행합니다. 이후, 페이징된 값을 context에 전달합니다. 기능이 잘 작동하는 확인하기 위해 페이징 간격을 1개로 설정했습니다.
이렇게 페이징 기능은 쉽게 구현했습니다.
다음은 최신순, 추천순에 따라 정렬한 뒤 사용자에게 보여줘야 합니다.
먼저 최신순, 추천순을 선택할 수 있는 select-form을 만들고 선택된 값에 따라 어떻게 정렬할지 알려주는 sort 값을 url에 추가해줍니다. searchForm을 수정하여 sort 값을 저장해야 페이지가 바뀌어도 정렬이 유지됩니다.
question_detail.html
<!-- 답변 -->
<div class="d-flex justify-content-between align-items-center my-3">
<h5 class="border-bottom my-3 py-2">{{ question.answer_set.count }}개의 답변이 있습니다.</h5>
<div class="d-flex align-items-center">
<form method="get" action="{% url 'pybo:detail' question.id %}">
<select name="sort" class="form-select" onchange="this.form.submit()">
<option value="latest" {% if sort == 'latest' %}selected{% endif %}>최신순</option>
<option value="most_voted" {% if sort == 'most_voted' %}selected{% endif %}>추천순</option>
</select>
</form>
</div>
</div>
<form id="searchForm" method="get" action="{% url 'pybo:detail' question.id %}">
<input type="hidden" id="page" name="page" value="{{ page }}">
<input type="hidden" id="sort" name="sort" value="{{ sort }}">
</form>
detail 함수도 살짝만 수정해주면 됩니다. sort 값을 가져와서 최신순, 추천순으로 정렬해주고 context에 sort 값을 전달해주면 끝입니다.
base_views.py
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
sort = request.GET.get('sort')
if sort == 'most_voted':
answer_list = Answer.objects.filter(question=question).order_by('-voter')
else:
answer_list = Answer.objects.filter(question=question).order_by('-create_date')
page = request.GET.get('page', '1')
paginator = Paginator(answer_list, 1)
answer_obj = paginator.get_page(page)
context = {'question': question, 'answer_list': answer_obj, 'sort': sort}
return render(request, 'pybo/question_detail.html', context)
이렇게 답변 페이징과 정렬 기능 추가를 완료했습니다.