2

I have a model with an ImageField that I'm indexing for search using Django Haystack, and I'd like to use the images in my search results. Correct me if I'm wrong, but you can not have an ImageField in a Django Haystack SearchQuerySet. So what is the best way to access the model ImageFields associated with a SearchQuerySet? Do I really have to loop over the model ids and add them to a separate QuerySet?

3 Answers 3

3

Accessing object hits the database.

If you don't want to hit the database you may index this way:

class MyIndex(SearchIndex, Indexable):
   ...
   photo_url = CharField()

   def prepare_photo_url(self, obj):
       return obj.image_field.path

source: http://django-haystack.readthedocs.org/en/latest/searchindex_api.html#prepare-foo-self-object

2
  • 2
    That only works for storages that support absolute paths, e.g. it will not work with the Amazon S3 storage from django-storages.
    – goldstein
    Commented Jul 9, 2015 at 17:26
  • @goldstein I believe this is the correct solution actually. If the storage doesn't support full path you can build it when showing the results. I use return obj.image_field.url instead of .path though. Commented Nov 1, 2016 at 16:40
3

I know the question is quite old but I had the same problem and I have information to share.

Lazy to read ? Jump to Solution.

Saying you have this model:

class School(models.Model):
  city = models.CharField(max_length=50)
  name = models.CharField(max_length=50)
  slug = models.SlugField(max_length=50, unique=True)
  cover = models.ImageField(upload_to='images/school-covers/')

You can see the ImageField: cover.

If you want to index the School model with Haystack with the autocomplete feature, you're supposed to do like this:

class SchoolIndex(indexes.SearchIndex, indexes.Indexable):
  name = indexes.EdgeNgramField(model_attr='name')
  city = indexes.EdgeNgramField(model_attr='city')
  slug = indexes.CharField(model_attr='slug')

  def get_model(self):
    return School

  def index_queryset(self, using=None):
    # Used when the entire index for model is updated.
    return self.get_model().objects.all()

As you can see I didn't include the ImageField because the ImageField object is not part of the indexes package.

This code snippets will index with the name and the city fields of the School model. Then in your AJAX view, you'll handle the search with a SearchQuerySet:

def search_ecoles(request):
  name = SearchQuerySet().autocomplete(name=request.POST.get('search_text',''))
  city = SearchQuerySet().autocomplete(city=request.POST.get('search_text',''))

  schools = name | city

  return render(request, 'website/ajax_search.html', {'schools' : schools})

So far I'm able to access the results in my template like this:

<ul>
  {% for school in schools %}
  <li>
    <span id="name"><a href="/school/{{ school.slug }}/">{{ school.name }}</a></span>
    <span id="city">City: {{ school.city }}</span>
  </li>
  {% endfor %}
</ul>

Solution

But maybe you'd like to access the cover ImageField. The easiest way and probably the neater is just to use the object inside the School object like so:

<img src="{{ school.object.cover.url }}" />
2

Just use result.object.my_image_field. The object attribute contains the full Django object associated with the search result.

Not the answer you're looking for? Browse other questions tagged or ask your own question.