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
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
-
2That only works for storages that support absolute paths, e.g. it will not work with the Amazon S3 storage from django-storages. 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
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 }}" />
Just use result.object.my_image_field
. The object
attribute contains the full Django object associated with the search result.