Search code examples
django-haystack

Filtering Haystack (SOLR) results by django_id


With Django/Haystack/SOLR, I'd like to be able to restrict the result of a search to those records within a particular range of django_ids. Getting these IDs is not a problem, but trying to filter by them produces some unexpected effects. The code looks like this (extraneous code trimmed for clarity):

def view_results(request,arg):
    # django_ids list is first calculated using arg...
    sqs = SearchQuerySet().facet('example_facet') # STEP_1
    sqs = sqs.filter(django_id__in=django_ids) # STEP_2

    view = search_view_factory(
        view_class=SearchView,
        template='search/search-results.html',
        searchqueryset=sqs,
        form_class=FacetedSearchForm
    )

    return view(request)

At the point marked STEP_1 I get all the database records. At STEP_2 the records are successfully narrowed down to the number I'd expect for that list of django_ids. The problem comes when the search results are displayed in cases where the user has specified a search term in the form. Rather than returning all records from STEP_2 which match the term, I get all records from STEP_2 plus all from STEP_1 which match the term.

Presumably, therefore, I need to override one/some of the methods in for SearchView in haystack/views.py, but what? Can anyone suggest a means of achieving what is required here?


Solution

  • After a bit more thought, I found a way around this. In the code above, the problem was occurring in the view = search_view_factory... line, so I needed to create my own SearchView class and override the get_results(self) method in order to apply the filtering after the search has been run with the user's search terms. The result is code along these lines:

    class MySearchView(SearchView):
    
        def get_results(self):
            search = self.form.search()
            # The ID I need for the database search is at the end of the URL,
            # but this may have some search parameters on and need cleaning up.
            view_id = self.request.path.split("/")[-1]
            view_query = MyView.objects.filter(id=view_id.split("&")[0])
    
            # At this point the django_ids of the required objects can be found.
            if len(view_query) > 0:
                view_item = view_query.__getitem__(0)
                django_ids = []
                for thing in view_item.things.all():
                   django_ids.append(thing.id)
                search = search.filter_and(django_id__in=django_ids)
            return search
    

    Using search.filter_and rather than search.filter at the end was another thing which turned out to be essential, but which didn't do what I needed when the filtering was being performed before getting to the SearchView.