I would like to display all results which match selected facets even though a search query has not been inserted. Similar to how some shop applications work e.g. Amazon
If anyone is still looking, there's a simple solution suggested in haystack code:
https://github.com/toastdriven/django-haystack/blob/master/haystack/forms.py#L34
class SearchForm(forms.Form):
def no_query_found(self):
"""
Determines the behavior when no query was found.
By default, no results are returned (``EmptySearchQuerySet``).
Should you want to show all results, override this method in your
own ``SearchForm`` subclass and do ``return self.searchqueryset.all()``.
"""
return EmptySearchQuerySet()
Following form display all the result if not query string is present. Now you can add custom filters.
from your_app.forms import NonEmptySearchForm
url(r'^your_url$',
SearchView(template='search.html',searchqueryset=sqs,form_class=NonEmptySearchForm), name='haystack_search'),
#Overridding because the default sqs is always none if no query string is present
class NonEmptySearchForm(SearchForm):
def search(self):
if not self.is_valid():
return self.no_query_found()
sqs = self.searchqueryset.auto_query(self.cleaned_data['q'])
if self.load_all:
sqs = sqs.load_all()
return sqs
Stumpy Joe Pete's answer is pretty spot on, but as he mentioned, the template if query or page.object_list
check is a little hacked. A better way of solving this would be to create your own SearchForm
which would still find something if q
is empty - will not repost that - AND to customize the SearchView
with something like:
class MySearchView(SearchView):
def get_query(self):
query = []
if self.form.is_valid():
for field in self.form:
if field.name in self.form.cleaned_data and self.form.cleaned_data[field.name]:
query.append(field.name+'='+str(self.form.cleaned_data[field.name]))
return ' AND '.join(query)
In most cases, you won't even be using the query
value, so you could just as well do a quick check if any of the fields is set and return True
or something like that.. or of course you can modify the output any way you want (I'm not even 100% sure my solution would work for all field types, but you get the idea).
Look at SearchQuerySet.
This should be possible if color and price has been defined in your SearchIndex:
sqs = SearchQuerySet().filter(color="blue", price__range=(10,100))
You can limit the query to certain models by adding models(Model) to the SearchQuerySet. So if you want to limit your query to the model Item use:
sqs = SearchQuerySet().filter(color="blue", price__range=(10,100)).models(Item)
I imagine you're using a search template similar to the one in the haystack getting started documentation. This view doesn't display anything if there is no query:
{% if query %}
{# Display the results #}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
The second problem is that the default search form's search()
method doesn't actually search for anything unless there's a query.
To get around this, I'm using a custom search form. Here's an abbreviated sample:
class CustomSearchForm(SearchForm):
...
def search(self):
# First, store the SearchQuerySet received from other processing.
sqs = super(CustomSearchForm, self).search()
if not self.is_valid():
return sqs
filts = []
# Check to see if a start_date was chosen.
if self.cleaned_data['start_date']:
filts.append(SQ(created_date__gte=self.cleaned_data['start_date']))
# Check to see if an end_date was chosen.
if self.cleaned_data['end_date']:
filts.append(SQ(created_date__lte=self.cleaned_data['end_date']))
# Etc., for any other things you add
# If we started without a query, we'd have no search
# results (which is fine, normally). However, if we
# had no query but we DID have other parameters, then
# we'd like to filter starting from everything rather
# than nothing (i.e., q='' and tags='bear' should
# return everything with a tag 'bear'.)
if len(filts) > 0 and not self.cleaned_data['q']:
sqs = SearchQuerySet().order_by('-created_date')
# Apply the filters
for filt in filts:
sqs = sqs.filter(filt)
return sqs
Also, don't forget to change the view:
{% if query or page.object_list %}
{# Display the results #}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
Actually, the view code is a little hackish. It doesn't distinguish query-less searches with no results from search with no parameters.
Cheers!