[django] 점프 투 장고 - 장고 심화 15

Joy·2020년 6월 30일
1

Django | 점프투장고

목록 보기
21/22

검색과 정렬

검색, 정렬기능 추가



검색기능

검색기능 추가하기 - 대상: 제목, 질문내용, 질문작성자, 답변작성자

from django.db.models import Q

kw = request.GET.get('kw', '')  # 검색어

if kw:
    question_list = question_list.filter(
        Q(subject__icontains=kw) |  # 제목검색
        Q(content__icontains=kw) |  # 내용검색
        Q(author__username__icontains=kw) |  # 질문 글쓴이검색
        Q(answer__author__username__icontains=kw)  # 답글 글쓴이검색
    ).distinct()
  • Q함수는 OR조건으로 데이터를 조회하기 위한 장고가 제공하는 함수(제목과 내용 그리고 글쓴이를 OR 조건으로 검색)

  • distinct 함수는 조회결과에 중복이 있을 경우 중복을 제거하고 리턴하게 해 주는 함수

GET

검색창

[question_list.html] 템플릿 수정

검색어 입력 텍스트 창 추가

<div class="row justify-content-end my-3">
        <div class="col-4 input-group">
            <input type="text" class="form-control kw" value="{{ kw|default_if_none:'' }}">
            <div class="input-group-append">
                <button class="btn btn-outline-secondary" type="button" id="btn_search">찾기</button>
            </div>
        </div>
    </div>
  • 텍스트창 class 속성에 kw라는 값을 추가 -> 스크립트에서 이 텍스트창의 값을 읽기 위해

검색폼

page와 kw를 동시에 GET으로 요청할 수 있는 searchForm 추가

[question_list.html]

<form id="searchForm" method="get" action="{% url 'index' %}">
    <input type="hidden" id="kw" name="kw" value="{{ kw|default_if_none:'' }}">
    <input type="hidden" id="page" name="page" value="{{ page }}">
</form>

페이징

기존 페이징 처리하는 부분도 ?page=1 처럼 직접 파라미터를 코딩하는 방식에서 값을 읽을 수 있도록 변경

 <a class="page-link" data-page="{{ question_list.next_page_number }}" href="#">다음</a>

기존: <a class="page-link" href="?page={{ question_list.next_page_number }}">다음</a>

  • href 속성에 직접 링크를 거는 방식 대신에 data-page 속성을 추가하여 값을 읽을수 있도록

스크립트

페이징과 검색을 처리할 수 있는 자바스크립트 블록 추가

{% block script %}
<script type='text/javascript'>
$(document).ready(function(){
    $(".page-link").on('click', function() {
        $("#page").val($(this).data("page"));
        $("#searchForm").submit();
    });

    $("#btn_search").on('click', function() {
        $("#kw").val($(".kw").val());
        $("#page").val(1);  // 검색버튼을 클릭할 경우 1페이지부터 조회한다.
        $("#searchForm").submit();
    });
});
</script>
{% endblock %}
  • 1st 스크립트: class 속성값으로 "page-link"라는 값을 가지고 있는 링크를 클릭 시 링크의 data-page 속성값을 읽어 폼 page 필드에 설정하여 폼을 요청하도록

  • 2nd 스크립트: 검색버튼을 클릭하면 검색어 텍스트창에 입력된 값을 폼 kw필드에 설정하여 폼을 요청하도록

검색기능

조회에 적용되도록 뷰 함수 수정


from django.db.models import Q

# 입력 파라미터
    page = request.GET.get('page', '1')  # 페이지
    kw = request.GET.get('kw', '')  # 검색어

    # 조회
    question_list = Question.objects.order_by('-create_date')
    if kw:
        question_list = question_list.filter(
            Q(subject__icontains=kw) |  # 제목검색
            Q(content__icontains=kw) |  # 내용검색
            Q(author__username__icontains=kw) |  # 질문 글쓴이검색
            Q(answer__author__username__icontains=kw)  # 답변 글쓴이검색
        ).distinct()
        
     context = {'question_list': page_obj, 'page': page, 'kw': kw}  # page와 kw가 추가되었다.
     return render(request, 'pybo/question_list.html', context)
  • filter 함수안에서 모델 속성에 접근하기 위해서는 이처럼 __ (언더바 두개) 를 이용하여 하위 속성에 접근

  • subject__icontains=kw : 제목에 kw문자열이 포함되었는지
    그냥 contains는 대소문자 구분

  • 템플릿에 입력으로 받은 page와 kw값을 전달하기위해 context에 page와 kw를 추가

테스트




정렬기능

질문목록을 정렬할 수 있는 기능

기준: 최신순/ 추천순/ 인기순(답변 수)

정렬조건

  • 템플릿에 정렬조건 추가하기

정렬폼

  • searchForm에 정렬기준 파라미터에 해당되는 so 필드 추가

[question_list.html]

<input type="hidden" id="so" name="so" value="{{ so }}">

스크립트

  • 정렬기준을 변경할때 searchForm 요청이 발생할 수 있도록 자바스크립트 추가
$(".so").on('change', function() {
        $("#so").val($(this).val());
        $("#page").val(1);
        $("#searchForm").submit();
    });
  • so라는 클래스를 가지고 있는 select박스의 값이 변경되면 선택된 값을 so 필드에 설정하여 폼 요청

정렬기능

  • 입력으로 받은 so 파라미터를 이용하여 질문목록을 정렬할 수 있도록 뷰수정

[base_views.py] index함수

  so = request.GET.get('so', 'recent')  # 정렬기준

 # 정렬
    if so == 'recommend':
        question_list = Question.objects.annotate(num_voter=Count('voter')).order_by('-num_voter', '-create_date')
    elif so == 'popular':
        question_list = Question.objects.annotate(num_answer=Count('answer')).order_by('-num_answer', '-create_date')
    else:  # recent
        question_list = Question.objects.order_by('-create_date')
  • Question.objects.annotate(num_voter=Count('voter')) : Question의 기존 속성에 num_voter 추가하는 개념.
    annotate 로 지정하면 filter나 oder_by에서 사용 가능.

  • num_voter 은 Count('voter')로 얻음

테스트

profile
roundy

0개의 댓글