장고:검색기능: 두 판 사이의 차이
둘러보기로 이동
검색으로 이동
(→탬플릿 수정) |
|||
(같은 사용자의 중간 판 4개는 보이지 않습니다) | |||
36번째 줄: | 36번째 줄: | ||
*<code>subject__contains</code> 대신 <code>subject__icontains</code> 형태를 사용하는 건 i를 붙였을 때 대소문자 구분없이 찾아주기 때문이다. | *<code>subject__contains</code> 대신 <code>subject__icontains</code> 형태를 사용하는 건 i를 붙였을 때 대소문자 구분없이 찾아주기 때문이다. | ||
== 탬플릿 수정 == | ==탬플릿 수정== | ||
검색창을 넣어야 하는 목록 탬플릿에 다음과 같이 추가한다.<syntaxhighlight lang="html+django"> | 검색창을 넣어야 하는 목록 탬플릿에 다음과 같이 추가한다.<syntaxhighlight lang="html+django"> | ||
<form id="searchForm" method="get" action="{% url 'pool:list' %}"> | <form id="searchForm" method="get" action="{% url 'pool:list' %}"> | ||
46번째 줄: | 46번째 줄: | ||
</div> | </div> | ||
</div> | </div> | ||
</syntaxhighlight>현재 페이지를 그대로 불러올 경우, url 대신 #앵커 형태로 넣을 수도 있다. | |||
=정렬기능= | |||
검색 뿐 아니라 날짜 순, 댓글 순, 추천 순 등으로 정렬해야 할 때가 있다. | |||
==탬플릿 수정== | |||
form을 이용해 정렬기준을 전달한다. | |||
검색 버튼을 누를 때 함께 전달되게 하기 위해 검색창을 정의하는 div 안에 다음과 같은 형태로 넣어준다.<syntaxhighlight lang="html+django"> | |||
<div class="col-2"> | |||
<select class="form-control so" name="ordering"> | |||
<option value="recent" {% if so == 'recent' %}selected{% endif %}>최신순</option> | |||
<option value="recommend" {% if so == 'recommend' %}selected{% endif %}>추천순</option> | |||
<option value="popular" {% if so == 'popular' %}selected{% endif %}>인기순</option> | |||
</select> | |||
</syntaxhighlight> | |||
==뷰 수정== | |||
다음과 같은 형태의 내용을 추가한다.<syntaxhighlight lang="python"> | |||
from django.db.models import Count # annotate에서 DB에 해당하는 무언가를 셀 때 사용하는 함수. | |||
def list(request): | |||
. | |||
. | |||
. | |||
# 정렬 기능 | |||
ordering = request.GET.get('ordering', 'recent') # 정렬기준 | |||
if ordering == 'recent': # 시간순 정렬 | |||
question_list = Question.objects.order_by('-create_date') | |||
elif ordering == 'popular': # 댓글순 정렬 | |||
question_list = Question.objects.annotate(num_answer=Count('answer')).order_by('-num_answer', '-create_date') | |||
elif ordering == 'recommend': # 추천순 정렬 | |||
question_list = Question.objects.annotate(num_voter=Count('voter')).order_by('-num_voter', '-create_date') | |||
else: # recent | |||
pass | |||
. | |||
. | |||
. | |||
context = { # ordering을 추가하여 반환해주자. 검색창에 검색어가 담겨 있게끔. | |||
'ordering': ordering, # 선택한 정렬순서는 다시 돌려준다. | |||
</syntaxhighlight>정렬기능에서 모델객체를 불러오기 때문에 검색기능 위에 두어야 한다. | |||
<br /> | |||
==페이징== | |||
그런데, 검색을 하고 나면... 페이징기능이 제대로 되먹지가 않는다; 검색에서 사용한 다양한 변수들이 전달되지 않기 때문인데, 2가지 선택지가 있다. | |||
#페이징 버튼을 form으로 바꾸어 hidden으로 각 변수들을 보내기. | |||
#JS를 이용하여 페이징버튼이 눌릴 때 form 안의 내용도 함께 제출되게끔 하기. | |||
페이징버튼마다 form을 만드는 건 굉장히 번거롭고, form 안의 내용이 바뀔 때마다 페이징 버튼에 대해 일일이 바꿔주어야 하는 불편함이 있다. 때문에 2번 방법을 사용한다. | |||
===탬플릿 수정=== | |||
====폼에 page정보 추가==== | |||
멀리 떨어진 form을 제출해야 하는데, 나는 그 방법은 모르겠다;; 하여, 기존 form 안에 다음을 추가한다.(page정보를 form에 담아 보내기 위해)<syntaxhighlight lang="html+django"> | |||
<input type="hidden" id="page" name="page" value="{{ page }}"> | |||
</syntaxhighlight> | </syntaxhighlight> | ||
= | ====페이지버튼 변형하기==== | ||
자바스크립트에서 작동시키기 위해 페이지버튼의 구성을 바꾼다. | |||
위의 형태에서 아래의 형태로.<syntaxhighlight lang="html+django"> | |||
<a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a> | |||
<a class="page-link" data-page="{{ page_number }}" href="#">{{ page_number }}</a> | |||
</syntaxhighlight><br /> | |||
===자바스크립트=== | |||
페이지 정보도 같이 제출되게끔 페이지정보를 form 안에 hidden 필드로 넣고 진행한다.<syntaxhighlight lang="javascript+django"> | |||
<!--페이지 버튼을 누르면 페이지 정보와 함께 검색폼의 내용도 제출되게끔. searchForm 안의 hidden으로 page를 넣는다.--> | |||
<script type='text/javascript'> | |||
$(document).ready(function(){ | |||
$(".page-link").on('click', function() { // page-link 클래스를 가진 버튼이 클릭되면 | |||
$("#page").val($(this).data("page")); // 해당 값을 page에 담고. | |||
$("#searchForm").submit(); // searchForm 안의 페이지에 담아 제출한다. | |||
}); | |||
// 검색버튼 클릭할 경우, 페이지번호를 받지 못하므로, 값을 넣어주어야 한다. | |||
$("#btn_search").on('click', function() { | |||
$("#page").val(1); // 검색버튼을 클릭할 경우 1페이지부터 조회한다. | |||
$("#searchForm").submit(); | |||
}); | |||
}); | |||
</script> | |||
</syntaxhighlight> |
2021년 3월 21일 (일) 13:41 기준 최신판
장고! 웹 프레임워크! 틀:장고
개요[편집 | 원본 편집]
검색기능은 DB에 쿼리하는 방식으로 이루어진다.
view 수정[편집 | 원본 편집]
목록을 조회하는 view를 수정한다.
다음과 같은 형태로 추가.
from django.db.models import Q # 검색을 위함. filter에서 OR조건으로 조회하기 위한 함수.(장고제공)
def list(request):
question_list = Question.objects.order_by('-create_date') # 일단 객체 목록을 받아온다.
keyword = request.GET.get('keyword', '') # 검색어. ''는 왜 필요할까? 없어도 되나?
if keyword: # 검색어가 있다면
result = [] # 검색결과를 담기 위한 리스트를 만든다.
keywords = keyword.split(' ') # 공백이 있는 경우 나눈다.
for kw in keywords: # 띄어쓰기로 검색을 하는 경우가 많으니까, 다 찾아줘야지.
result += question_list.filter( # 검색해서 검색결과에 더한다.
Q(subject__icontains=kw) | # 제목검색
Q(content__icontains=kw) | # 내용검색
Q(author__username__icontains=kw) | # # question모델의 상위인 user모델의 username에서 검색.
Q(answer__author__username__icontains=kw) # 하위모델인 answer모델의 참조인 user모델의 username에서 검색.
).distinct() # 중복된 내용이 있으면 제거하는 함수.
question_list = result # 모은 결과를 리스트에 담는다.
.
.
.
context = { # keyword를 추가하여 반환해주자. 검색창에 검색어가 담겨 있게끔.
'keyword': keyword, # 검색어는 다시 돌려준다.
- POST방식이 아니라 GET으로 받아오는 것은 뒤로가기 버튼을 누를 때 '만료된 페이지입니다'라는 문구가 뜨기 때문이다. 그럼 다시 찾아들어가야 하고.. 불편해.
- ('만료된 페이지입니다' 문구는 POST요청 시 중복요청을 방지하기 위해 발생시키는 오류이다.)
subject__contains
대신subject__icontains
형태를 사용하는 건 i를 붙였을 때 대소문자 구분없이 찾아주기 때문이다.
탬플릿 수정[편집 | 원본 편집]
검색창을 넣어야 하는 목록 탬플릿에 다음과 같이 추가한다.
<form id="searchForm" method="get" action="{% url 'pool:list' %}">
<div class="input-group mb-3">
<input type="text" class="form-control" name="keyword" placeholder="여따 검색하쇼" value="{{ keyword|default_if_none:'' }}">
<div class="input-group-append">
<input class="btn btn-outline-secondary" type="submit" id="btn_search" value="검색"></input>
</form>
</div>
</div>
현재 페이지를 그대로 불러올 경우, url 대신 #앵커 형태로 넣을 수도 있다.
정렬기능[편집 | 원본 편집]
검색 뿐 아니라 날짜 순, 댓글 순, 추천 순 등으로 정렬해야 할 때가 있다.
탬플릿 수정[편집 | 원본 편집]
form을 이용해 정렬기준을 전달한다.
검색 버튼을 누를 때 함께 전달되게 하기 위해 검색창을 정의하는 div 안에 다음과 같은 형태로 넣어준다.
<div class="col-2">
<select class="form-control so" name="ordering">
<option value="recent" {% if so == 'recent' %}selected{% endif %}>최신순</option>
<option value="recommend" {% if so == 'recommend' %}selected{% endif %}>추천순</option>
<option value="popular" {% if so == 'popular' %}selected{% endif %}>인기순</option>
</select>
뷰 수정[편집 | 원본 편집]
다음과 같은 형태의 내용을 추가한다.
from django.db.models import Count # annotate에서 DB에 해당하는 무언가를 셀 때 사용하는 함수.
def list(request):
.
.
.
# 정렬 기능
ordering = request.GET.get('ordering', 'recent') # 정렬기준
if ordering == 'recent': # 시간순 정렬
question_list = Question.objects.order_by('-create_date')
elif ordering == 'popular': # 댓글순 정렬
question_list = Question.objects.annotate(num_answer=Count('answer')).order_by('-num_answer', '-create_date')
elif ordering == 'recommend': # 추천순 정렬
question_list = Question.objects.annotate(num_voter=Count('voter')).order_by('-num_voter', '-create_date')
else: # recent
pass
.
.
.
context = { # ordering을 추가하여 반환해주자. 검색창에 검색어가 담겨 있게끔.
'ordering': ordering, # 선택한 정렬순서는 다시 돌려준다.
정렬기능에서 모델객체를 불러오기 때문에 검색기능 위에 두어야 한다.
페이징[편집 | 원본 편집]
그런데, 검색을 하고 나면... 페이징기능이 제대로 되먹지가 않는다; 검색에서 사용한 다양한 변수들이 전달되지 않기 때문인데, 2가지 선택지가 있다.
- 페이징 버튼을 form으로 바꾸어 hidden으로 각 변수들을 보내기.
- JS를 이용하여 페이징버튼이 눌릴 때 form 안의 내용도 함께 제출되게끔 하기.
페이징버튼마다 form을 만드는 건 굉장히 번거롭고, form 안의 내용이 바뀔 때마다 페이징 버튼에 대해 일일이 바꿔주어야 하는 불편함이 있다. 때문에 2번 방법을 사용한다.
탬플릿 수정[편집 | 원본 편집]
폼에 page정보 추가[편집 | 원본 편집]
멀리 떨어진 form을 제출해야 하는데, 나는 그 방법은 모르겠다;; 하여, 기존 form 안에 다음을 추가한다.(page정보를 form에 담아 보내기 위해)
<input type="hidden" id="page" name="page" value="{{ page }}">
페이지버튼 변형하기[편집 | 원본 편집]
자바스크립트에서 작동시키기 위해 페이지버튼의 구성을 바꾼다.
위의 형태에서 아래의 형태로.
<a class="page-link" href="?page={{ page_number }}">{{ page_number }}</a>
<a class="page-link" data-page="{{ page_number }}" href="#">{{ page_number }}</a>
자바스크립트[편집 | 원본 편집]
페이지 정보도 같이 제출되게끔 페이지정보를 form 안에 hidden 필드로 넣고 진행한다.
<!--페이지 버튼을 누르면 페이지 정보와 함께 검색폼의 내용도 제출되게끔. searchForm 안의 hidden으로 page를 넣는다.-->
<script type='text/javascript'>
$(document).ready(function(){
$(".page-link").on('click', function() { // page-link 클래스를 가진 버튼이 클릭되면
$("#page").val($(this).data("page")); // 해당 값을 page에 담고.
$("#searchForm").submit(); // searchForm 안의 페이지에 담아 제출한다.
});
// 검색버튼 클릭할 경우, 페이지번호를 받지 못하므로, 값을 넣어주어야 한다.
$("#btn_search").on('click', function() {
$("#page").val(1); // 검색버튼을 클릭할 경우 1페이지부터 조회한다.
$("#searchForm").submit();
});
});
</script>