Innovate anywhere, anytime withruncode.io Your cloud-based dev studio.
Django

Implement Search with Django-haystack and Elasticsearch Part-1

2022-07-20

Haystack works as a search plugin for Django. You can use different backends Elastic-search, Whose, Sorl, Xapian to search objects. All backends work with the same code. In this post, I am using elastic search as backend.

Installation:

pip install django-haystack

Configuration:

add haystack to installed apps

INSTALLED_APPS=[

               'django.contrib.admin',
               'django.contrib.auth',
               'django.contrib.contenttypes',
               'django.contrib.sessions',
               'django.contrib.sites',
               #add haystack here
               'haystack',
               'books'
    ]

Settings:

Add back-end settings for the haystack.

HAYSTACK_CONNECTIONS = {
              'default': {
                    'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
                    'URL': 'http://127.0.0.1:9200/',
                    'INDEX_NAME': 'haystack_books',
              },
    }

Above settings for elastic search.

Add signal processor for the haystack. This signal will update objects in an index. 

HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

For This tutorial, I am using below as a model.

books/models.py:

class Book(models.Model):
        title = models.CharField(max_length=100, unique=True)
        slug = models.SlugField(unique=True)
        created_on = models.DateTimeField(auto_now_add=True)
        description = models.TextField()
        authors = models.ManyToManyField(settings.AUTH_USER_MODEL)
        
        def __unicode__(self):
            return self.title

SearchIndex:

The purpose of indexing objects is to optimize speed and performance in finding relevant documents for a given search query.
    With search index haystack determines what data should be placed in the index. In haystack, you write a unique index for each model.

create a new file in books/search_indexes.py below code goes

from haystack import indexes
    from books.models import Book

    class BookIndex(indexes.SearchIndex, indexes.Indexable):
        text = indexes.CharField(document=True, use_template=True, template_name="search/book_text.txt")
        title = indexes.CharField(model_attr='title')
        authors = indexes.CharField()

        def get_model(self):
            return Book

        def prepare_authors(self, obj):
            return [ author.name for author in obj.authors.all()]

        def index_queryset(self, using=None):
            return self.get_model().objects.all()

search index will be created by subclassing both haystack.Indexes.SearchIndex and haystack.Indexes.Indexable. Specify index field types by indexes field types(similar to models).

in above index class get_model method used to define a model which you want to create indexes. prepare_fieldname method used to define data for indexing.

Haystack will use a template to index data. these index syntaxes are similar to Django template tags.

templates/search/book_text.txt

{{ object.title }}
    {% for a in authors%}
        {{ a }}
    {% endfor %}

Setup:

urls.py

urlpatterns = patterns(
        # other urls
        url(r'^search/', include('haystack.urls')),
    )

build index:

Python manage.py rebuild_index

search query form.   

<form action="/search" method="get">
        <input name="q" type="text" />
        <input type="submit" />
    </form>

input field q is mandatory for searching.

Display search results:

belove code goes in templates/search/search.html

{% for result in page.object_list %}
{{ result.object.title }}
{{ result.object.description }}
{{ result.object.created_on }}
        {% empty %}           
No results found.
        {% endfor %}