검색, 정렬기능 추가
검색기능 추가하기 - 대상: 제목, 질문내용, 질문작성자, 답변작성자
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 함수는 조회결과에 중복이 있을 경우 중복을 제거하고 리턴하게 해 주는 함수
검색어 입력 텍스트 창 추가
<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>
page와 kw를 동시에 GET으로 요청할 수 있는 searchForm 추가
<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>
페이징과 검색을 처리할 수 있는 자바스크립트 블록 추가
{% 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를 추가
질문목록을 정렬할 수 있는 기능
기준: 최신순/ 추천순/ 인기순(답변 수)
<input type="hidden" id="so" name="so" value="{{ so }}">
$(".so").on('change', function() {
$("#so").val($(this).val());
$("#page").val(1);
$("#searchForm").submit();
});
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')로 얻음