My [Adobe software updates][asu] app (which uses [Haystack][haystack] + [Django][django] to provide a search feature) has a very inefficient search results template, where for each search result the template links back to the update’s related product page.
The meat of the search results template looks something like this:
{% for result in page.object_list %}
{% endfor %}
The reverse URL lookup triggers a separate SQL query to find the related product object’s slug field for each object in the results list, and that slows down the page response significantly.
For a regular queryset you would [tell Django to fetch the related objects][select-related] in one go when populating the template context in order to avoid the extra queries, but in this case `page.object_list` is generated by Haystack. So how to tell Haystack to use `select_related()` for the queryset?
It is easy. When you register a model to be indexed with Haystack for searching, you have to define a `SearchIndex` model, and you can also override the [`read_queryset()` method that is used by Haystack to get a Django queryset][rq]:
# myapp.search_indexes.py
from haystack import indexes, site
from myapp.models import MyModel
class MyModelIndex(indexes.SearchIndex):
# Indexed fields declared here
…
def get_model(self):
return MyModel
def read_queryset(self):
return self.model.objects.select_related()
site.register(MyModel, MyModelIndex)
And that solved it for me. Shaves three quarters off the execution time.
PS This all pertains to Django 1.4 and Haystack 1.2.7.
PPS Also pertains to a version of my Adobe software updates page that I haven’t deployed quite yet.
[haystack]: http://haystacksearch.org/
[django]: https://www.djangoproject.com/
[asu]: http://reliablybroken.com/wavesinspace/adobe/
[select-related]: https://docs.djangoproject.com/en/1.4/ref/models/querysets/#select-related
[rq]: http://django-haystack.readthedocs.org/en/v1.2.7/searchindex_api.html#read-queryset