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?

Danny Beckett
  • 20,529
  • 24
  • 107
  • 134
HighLife
  • 4,218
  • 7
  • 40
  • 56

3 Answers3

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

MechanTOurS
  • 1,485
  • 2
  • 15
  • 18
  • 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 Jul 09 '15 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. – Diego Jancic Nov 01 '16 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 }}" />
David Guyon
  • 2,759
  • 1
  • 28
  • 40
2

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

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444