django haystack whoosh 검색 구현
django로 만들고 있는 웹에 검색기능을 구현해봅시다. medium 포스팅이 이해하는데 정말 많은 도움이 되었습니다. 감사합니다.
공식문서 : https://django-haystack.readthedocs.io/en/master/tutorial.html
참고 : https://medium.com/@whj2013123218/%EC%9E%A5%EA%B3%A0-django-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8%EC%97%90-%EA%B2%80%EC%83%89%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0-haystack%EA%B3%BC-whoosh%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B8%B0%EC%B4%88-%EA%B2%80%EC%83%89%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84-19aa7f8040db
우선 검색할 내용의 기반이 되는 모델이 있어야합니다.
저는 제가 만들어 놓은 모델을 예제 소스로 가져왔습니다.
#posts/models.py
class Post(models.Model, HitCountMixin):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
created_at = models.DateTimeField(auto_now=True)
text = RichTextUploadingField()
title = models.CharField(max_length=100)
link = models.URLField()
설치
pip install django-haystack
pip install whoosh
그리고 settings.py에 아래와 같은 값을 추가해줍니다.
INSTALLED_APPS =[
...
'haystack',
]
import os
...
WHOOSH_INDEX = os.path.join(BASE_DIR, 'whoosh_index')
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
'PATH': WHOOSH_INDEX,
},
}
search_indexes.py 생성
import datetime
from haystack import indexes
from .models import Post
class NoteIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True, template_name='search/post_text.txt')
author = indexes.CharField(model_attr='user')
pub_date = indexes.DateTimeField(model_attr='created_at')
def get_model(self):
return Post
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.all()
해당 models.py이 있는 폴더안에 search_indexes.py을 만들고 위의 코드를 붙여넣는다.
여기서 Post
는 필자의 모델 이름이므로 본인의 모델 이름에 맞게 수정한다.
model_attr
도 본인이 사용하고 있는 모델내의 필드 이름과 같아야 한다.
text
에 있는 document=True
는 한 필드에만 적용될 수 있고
이를 통해 Haystack과 검색 엔진이 text
를 주요 필드로 삼아 검색하게 된다.
get_model
에는 사용하고 싶은 모델의 이름을 리턴해주면 된다.
Post 모델을 검색하게 할 것이므로 Post
를 리턴했다.
template 생성
use_template=Ture
를 보면 알수있듯이 우리는 템플리는 사용한다고 했으므로 txt template을 하나 만들어야 한다. template_name
에 지정한대로 폴더와 파일을 만들어주자. 공식문서에 나와있는 것처럼 이름은 모델명_필드명. txt
로 하는것이 관리하기 편하다. 필자는 모델이 Post
이고 document=True
가 돼있는 필드는 text
이므로 post.text.txt
로 생성했다.
그리고 txt 파일안에 아래의 코드를 붙여 넣어주자
{{ object.title }}
{{ object.user.get_full_name }}
{{ object.text }}
여기서도 각 필드부분 즉 title, user, text는 본인의 모델에 맞게 변경해야 한다.
모델의 필드를 보고 참고해서 수정해주자.
필자의 디렉토리 구조는 아래와 같이 되어있다.
view를 위한 설정
urls.py에서 인식할 수 있게 코드를 추가한다.
path('search/', include('haystack.urls')),
Search Template을 만들자
방금 모델명_필드명.txt
파일을 만든 search
폴더 안에 search.html
을 만든다.
아래의 코드를 붙여넣는다.
{% block content %}
<h2>Search</h2>
<form method="get" action=".">
<table>
{{ form.as_table }}
<tr>
<td> </td>
<td>
<input type="submit" value="Search">
</td>
</tr>
</table>
{% if query %}
<h3>Results</h3>
{% for result in page.object_list %}
<p>
<a href="{{ result.object.get_absolute_url }}">{{ result.object.title }}</a>
</p>
{% empty %}
<p>No results found.</p>
{% endfor %}
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}<a href="?q={{ query }}&page={{ page.previous_page_number }}">{% endif %}« Previous{% if page.has_previous %}</a>{% endif %}
|
{% if page.has_next %}<a href="?q={{ query }}&page={{ page.next_page_number }}">{% endif %}Next »{% if page.has_next %}</a>{% endif %}
</div>
{% endif %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</form>
{% endblock %}
그 후에 python manage.py rebuild_index
명령어를 쳐서 검색할 내용을 모아준다.
...\Virenv\Project\versio>python manage.py rebuild_index
WARNING: This will irreparably remove EVERYTHING from your search index in connection 'default'.
Your choices after this are to restore from backups or rebuild via the `rebuild_index` command.
Are you sure you wish to continue? [y/N] y
Removing all documents from your index because you said so.
All documents removed.
Indexing 3 posts
3 posts만 DB에 넣어놨으므로 성공하면 위와 같이 메세지가 뜬다.
http://localhost:8000/search/에 접속해서 검색을 해보자
검색결과가 알맞게 뜨면 성공이다.
190513 추가
자동 인덱싱이 안되는 줄 알았는데 영어로 검색해보니 쉽게 나왔다.
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
settings,py에 한줄만 추가해주면 된다.