Django Query Filter를 통해 전체, 작성자, 제목, 내용별 검색을 구현합니다.
1. views.py 수정
게시글의 검색기능 구현은 Django의 쿼리 필터를 통해 쉽게 구현할 수 있습니다. 템플릿에 select 태그로 전체, 제목+내용, 제목, 내용, 작성자별 검색 타입과 검색어를 입력받아 form GET 메소드로 요청을 받습니다. view에서 form의 값들이 GET으로 넘어와 url 뒤에 /?type=’검색타입’&q=’검색어’&page=’페이지’ 와 같은 형식으로 파라미터들을 받게 되면 request 객체에 있는 get은 딕셔너리 형으로 변환하여 저장하게 됩니다. 따라서 request.GET.get(‘파라미터값’, ‘ ‘) 과 같은 형식으로 파라미터를 전달받고 쿼리 필터를 적용하여 반환하는 소스를 이전 포스팅에서 구현한 NoticeListView의 get_queryset에 아래와 같이 추가합니다.
return search_notice_list else: messages.error(self.request, '검색어는 2글자 이상 입력해주세요.') return notice_list
get_queryset에 추가된 소스를 보시면 search_keyword, search_type의 변수명으로 파라미터의 값들을 저장합니다. 그 후 검색어인 search_keyword의 유무와 검색어의 길이를 판별해 검색타입인 search_type으로 다시 구분하여 각각의 필터를 적용합니다.
전체타입과 제목+내용 타입과 같이 두가지 이상의 필터 조건을 적용하기 위하여 django.db.models의 Q를 import합니다. 그리고 전체 쿼리셋에서 search_keyword가 포함되어있는 쿼리셋만 가져오기 위해 ‘필드명’__icontains = ‘조건값’ 형식으로 필터를 적용합니다. __icontains는 대소문자를 구분하지 않고 조건값이 포함되어 있는 데이터를 가져옵니다.
그리고 템플릿에서도 사용자가 검색한 검색결과를 ‘<검색어> 검색결과 입니다.’ 와 같이 표시하고, 선택한 검색타입을 계속 유지하기 위해 context로 search_keyword와 search_type을 넘겨주는 소스를 NoticeListView의 get_context_data에 추가합니다.
{% if notice_list %} {% for notice in notice_list %} <tr class="text-center"> <td>{{ notice.id }}</td> <td>{{ notice.title|truncatechars:30 }}</td> <td>{{ notice.writer }}</td> <td>{{ notice.registered_date|date:'Y. m. d' }}</td> <td>{{ notice.hits }}</td> </tr> {% endfor %} {% else %} <!-- 게시글 쿼리셋이 존재하지 않을 때 --> {% if q %} <!-- 검색어가 있어 q가 context로 넘어오면 검색결과가 없음 --> <tr class="text-center"> <td colspan="5"> 일치하는 검색 결과가 없습니다. </td> </tr> {% else %} <!-- q가 없으면 검색어가 아니며 게시글이 존재하지 않으므로 게시글 미작성 --> <tr class="text-center"> <td colspan="5"> 작성된 게시글이 없습니다. </td> </tr> {% endif %} {% endif %}
검색결과 수가 많아 페이지네이션이 적용되었을 때 페이지를 넘기면 검색결과가 풀려버리는 버그가 발생합니다. 이 프로젝트에서는 따로 검색 View를 구현하지 않고 ListView로 묶어 구현했기 때문에 페이지네이션 부분의 href 소스도 파라미터를 전달 할 수 있도록 아래와 같이 수정해줍니다.