개발

점프 투 장고 추가 기능(답변 페이징과 정렬)

wafla 2024. 11. 5. 19:41

답변 페이징과 정렬

점프 투 장고의 첫 번째 숙제 답변 페이징과 정렬 기능을 구현해봅시다.

새로운 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)

 

이렇게 답변 페이징과 정렬 기능 추가를 완료했습니다.