UsageΒΆ
For a minimal investment of time, Django Simple Elasticsearch offers a number of perks. Implementing a class
with the ElasticsearchIndexMixin
lets you:
- initialize your Elasticsearch indices and mappings via the included
es_manage
management command - perform Elasticsearch bulk indexing via the same
es_manage
management command - perform Elasticsearch bulk indexing as well as individual index/delete requests on demand in your code
- connect the available
ElasticsearchIndexMixin
save and delete handlers to Django’s available model signals (iepost_save
,post_delete
)
Let’s look at an example implementation of ElasticsearchIndexMixin
. Here’s a couple of blog-related Models
in a models.py
file:
class Blog(models.Model):
name = models.CharField(max_length=50)
description = models.TextField()
class BlogPost(models.Model):
blog = models.ForeignKey(Blog)
slug = models.SlugField()
title = models.CharField(max_length=50)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
To start with simple_elasticsearch
, you’ll need to tell it that the BlogPost
class implements the
ElasticsearchIndexMixin
mixin, so in your settings.py
set the ELASTICSEARCH_TYPE_CLASSES
setting:
ELASTICSEARCH_TYPE_CLASSES = [
'blog.models.BlogPost'
]
If you do not add this setting, everything will still work except for the es_manage
command - it won’t know
what indices to create, type mappings to set or what objects to index. As you add additional
ElasticsearchIndexMixin
-based index handlers, add them to this list.
All right, let’s add in ElasticsearchIndexMixin
to the BlogPost
model. Only pertinent changes from the
above models.py
are shown:
from simple_elasticsearch.mixins import ElasticsearchIndexMixin
...
class BlogPost(models.Model, ElasticsearchIndexMixin):
blog = models.ForeignKey(Blog)
slug = models.SlugField()
title = models.CharField(max_length=50)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
@classmethod
def get_queryset(cls):
return BlogPost.objects.all().select_related('blog')
@classmethod
def get_index_name(cls):
return 'blog'
@classmethod
def get_type_name(cls):
return 'posts'
@classmethod
def get_type_mapping(cls):
return {
"properties": {
"created_at": {
"type": "date",
"format": "dateOptionalTime"
},
"title": {
"type": "string"
},
"body": {
"type": "string"
},
"slug": {
"type": "string"
},
"blog": {
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
}
}
}
}
}
@classmethod
def get_document(cls, obj):
return {
'created_at': obj.created_at,
'title': obj.title,
'body': obj.body,
'slug': obj.slug,
'blog': {
'id': obj.blog.id,
'name': obj.blog.name,
'description': obj.blog.description,
}
}
With this mixin implementation, you can now use the es_manage
management command to bulk reindex all BlogPost
items. Note that there are additional @classmethods
you can override to customize functionality. Sane defaults
have been provided for these - see the source for details.
Of course, our BlogPost
implementation doesn’t ensure that your Elasticsearch index is updated every time you
save or delete - for this, you can use the ElasticsearchIndexMixin
built-in save and delete handlers.
from django.db.models.signals import post_save, pre_delete
...
post_save.connect(BlogPost.save_handler, sender=BlogPost)
pre_delete.connect(BlogPost.delete_handler, sender=BlogPost)
Awesome - Django’s magic is applied.
TODO:
- add examples for more complex data situations
- add examples of using
ElasticsearchForm
to derive your own search forms - add examples of using
es_manage
management command options - add examples/scenarios when to use
post_indices_create
andpost_indices_rebuild
signals (ie. adding percolators to new indices)