Haystack Accessing Stored Fields

May 20, 2010

When you define a search_indexes.py file in Haystack, you can specify additional fields taken from the model. These fields are stored in the index:

import datetime
from haystack.indexes import *
from haystack import site
from myproject.xmlclass.models import XmlClass

class XmlClassIndex(SearchIndex):
    text = CharField(document=True, use_template=True)
    project = CharField(model_attr='project__name')

site.register(XmlClass, XmlClassIndex)

This example adds a project field to the index, which will contain the name attribute on the foreign key called Project. This uses the same double underscore syntax as the query lookup code in Django.

Search Results

This field can be included in the search results by using the get_stored_fields attribute on the result:

{% for result in page.object_list %}
<p><a href="/project/{{result.get_stored_fields.project}}">{{result.get_stored_fields.project}}</a>:
       <a href="{{ result.object.get_absolute_url }}">{{ result.object.name }}</a></p>
{% empty %}  
<p>No results found.</p>
{% endfor %}

You can see here that the project field was referenced in the template as result.get_stored_fields.project.

Search Form

To add the project as an option on the search form, limiting results to objects just from that project, was more involved.

First of all, rather than importing urls from haystack, we needed to specify the single url manually in urls.py:

url(r'^search/$', SearchView(form_class=MySearchForm), name='haystack.views.haystack_search'),

MySearchForm, referenced here, is a subclass of the haystack ModelSearchForm:

from haystack.forms import ModelSearchForm
from django import forms
from myproject.project.models import Project

class MySearchForm(ModelSearchForm):
    project = forms.ModelChoiceField(queryset=Project.objects.all(), required=False)

    def search(self):
        lQuerySet = super(MySearchForm, self).search()

        if self.cleaned_data['project']:
            lQuerySet = lQuerySet.filter(project=self.cleaned_data['project'])

        return lQuerySet

This adds a new droplist to the form, and populates it with all the projects in the database.

It then redefines search() so that the queryset returned from the default search() is further refined to limit to the project, where the project has been specified.