Mr. Editor-in-chief Mr. Editor-in-chief September 14, 2024 Updated April 24, 2026

Integrate ElasticSearch with Django

Start an elasticsearch docker container

  • cd ~/mdblog cd into /path/to/django-project/base_dir
  • touch compose.yaml

@compose.yaml

services:
  elasticsearch:
    container_name: elasticsearch
    image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
    volumes:
      - esdata01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false

volumes:
  esdata01:
  • docker compose up -d
  • curl localhost:9200 to test if the elasticsearch instance is running

Config Django Project

  • pip install django-elasticsearch-dsl

@settings.py

......
INSTALLED_APPS = [
......
    'django_elasticsearch_dsl',
......
]
......
ELASTICSEARCH_DSL = {
    'default': {
        'hosts': 'http://localhost:9200'
    }
}
......

@posts/models.py

......
Class Post(models.Model):
......
    content = MDTextField()
......
    # MDTextField() can't be processed by ElasticSearch
    def type_to_string(self): 
        """Convert the type field to its string representation
        """
        return str(self.content)
  • touch posts/documents.py Create a documents.py inside a Django app (e.g. named posts)

@posts/documents.py

from django_elasticsearch_dsl import Document, fields
from django_elasticsearch_dsl.registries import registry

from .models import Post

# We need to run 'python manage.py search_index --rebuild' each time after we change something here
@registry.register_document
class PostDocument(Document):
    content = fields.TextField(attr="type_to_string")

    class Index:
        name = 'posts'
        settings = {'number_of_shards': 1, 'number_of_replicas': 0}

    class Django:
        model = Post
        fields = ['title', 'created_on', 'slug']

@posts/views.py

......
from .documents import PostDocument
from elasticsearch_dsl.query import MultiMatch
......
class PostListView(ListView):
    model = Post
    template_name = 'posts/post_list.html'
    paginate_by = 10

    # Search function
    def get_queryset(self):
        object_list = super().get_queryset()
        q = self.request.GET.get('q')
        if q:
            # Implement Elastic Search
            query = MultiMatch(query=q, fields=['title', 'content'], fuzziness='AUTO')
            object_list = PostDocument.search().query(query)
        return object_list
  • Replace <a href="{{ post.get_absolute_url }}"> with <a href="/post/{{ post.slug }}/"> @posts/post_list.html

Reference