How to integrate haystack search with Django admin
Recently, I had to integrate Haystack with Django admin so as to be able to perform a full text search just via the admin. Looking around for resources on the internet, I came across this page in Haystack's docs. Turns out Haystack has provided a solution to ease the integration of Haystack with Django admin.
Well, sort of. You see, the solution they've provided in the docs is only partial. You can do exactly what the docs instruct, yet the example won't work.
The solution is to set the search_fields
attribute in your admin class.
The value of search_fields
can be set to any field that is present in your model.
Haystack's SearchModelAdmin
class will override it and will search your
search index's text
field.
Below is an example that would provide a little more illustration to the solution:
# models.py
class Article(models.Model):
title = models.CharField(max_length=100)
body = models.TextField() # we want to search this field
pub_date = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-pub_date'] # show newest articles first
I'm not gonna show how to set up Haystack search index. This post is not about that. Hopefully, you've already done that. If not, you can read Haystack's docs about that.
Let's see the admin:
# admin.py
from django.contrib import admin
from haystack.admin import SearchModelAdmin
from .models import Article
class ArticleAdmin(SearchModelAdmin):
# set the search_fields attribute to a field present in Article
search_fields = ('title',) # or ('body',) it doesn't really matter
We have inherited our admin class from SearchModelAdmin
class provided
by Haystack. This will take the search query argument, search the index, then
return the results.
That's it! Try searching for something in Django admin, it should be working (if it's not, have you updated or created a search index yet?).
Heads up¶
There are two downsides of integrating Haystack search with Django admin.
1. The checkboxes on the left of the changelist page table will not appear in the search results. I don't find this a big issue, though. If a find a solution to this, I will post it here.
2. The search results will not be ordered as expected. For example, we've
ordered the Articles by pub_date
in reverse order so that newest articles
appear first. But this ordering won't apply to haystack's search results.
They will appear, in this case, as oldest first.
There's a workaround for that. You might not like it. I don't like. Having said that, I used that workaround for the project since I was on a deadline. And now I'm too lazy to look for another solutions. Anyways, here it is:
Firstly, make sure that you've included the model field in your haystack search index
class that you want to use for ordering. So in this case, that field is pub_date
.
What I mean is, you have to included pub_date
in your search index if you want
to use it for ordering. Example:
class ArticleIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
pub_date = indexes.DateTimeField(model_attr='pub_date')
Now copy the haystack/admin.py
file to your project or app's directory. Save it
as search_admin.py
. Open it in a text editor. You'll see a class defined as
SearchChangeList
. You'll have to change a line inside it. Find the following
line in that class:
sqs = SearchQuerySet(self.haystack_connection).models(self.model).auto_query(request.GET[SEARCH_VAR]).load_all()
Now, all you have to do is append .order_by('field_name')
to that line. In this case,
.order_by('-pub_date')
("-
" means reverse ordering). Example:
sqs = SearchQuerySet(self.haystack_connection
).models(self.model
).auto_query(request.GET[SEARCH_VAR]
).load_all().order_by('-pub-date')
Finally, in your admin.py
file, you've to import the SearchModelAdmin
from this file,
instead of from haystack.admin
.
from haystack.admin import SearchModelAdmin # Replace this
from search_admin import SearchModelAdmin # with this
I know, this workaround is really ugly. The more preferable way would be to
override the code, instead of copying and changing it. Believe me, I tried that.
But if you go through the source code in haystack/admin.py
file, you'll see
overriding is not possible. Well, it is possible, but, it would still be ugly.
Just go through the code, you'll see. If you have a better workaround, I'd love to know.