Search code examples
djangoelasticsearchdjango-haystack

Selecting models to use with SearchQuerySet


I've got some code which contains a search function along the lines of the following:

def searchHay(request):
    content = sorted(request.GET.getlist('content', ''))
    sqs =  SearchQuerySet().facet('this').facet('that').facet('the_other')

    # This if/else block is perhaps not a very good solution...
    if "things" in content and "stuff" in content:
        sqs = sqs.models(Things, Stuff)
    elif "things" in content:
        sqs = sqs.models(Things)
    elif "stuff" in content:
        sqs = sqs.models(Stuff)

    sqs = sqs.order_by('sort_field')
    view = search_view_factory(
        view_class=FacetedSearchView,
        template='search/search.html',
        searchqueryset=sqs,
        form_class=AllFacetedSearchForm
    )
    return view(request)

As you can see, different models are searched depending on some options selected by the user when submitting a form, which get passed here as 'content'. This works, but becomes very cumbersome as the number of models increases. If anyone has any suggestions for a more elegant way of doing this then I would be interested to know what they are.


Solution

  • One easy solution could be to have "independant ifs", instead of:

    # This if/else block is perhaps not a very good solution...
    if "things" in content and "stuff" in content:
        sqs = sqs.models(Things, Stuff)
    elif "things" in content:
        sqs = sqs.models(Things)
    elif "stuff" in content:
        sqs = sqs.models(Stuff)
    

    You could have:

    if "things" in content:
        sqs = sqs.models(Things)
    
    if "stuff" in content:
        sqs = sqs.models(Stuff)
    

    With this you don't need to manage "multiple selections", if there is things & stuff in content, it will automatically add both filters. And if you need to add more models in the future, just have to add one if for each model.

    I thought if you do sqs = sqs.models(Things) and then sqs = sqs.models(Stuff) the result will be 0 or empty but...

    I tested it in console to make sure and my surprise was...

    1. sqs = sqs.models(Things)
    2. sqs.count() <-- this return let's say 100
    3. sqs = sqs.models(Stuff)
    4. sqs.count() <-- This will return 100 + the objects of model Stuff

    So you could have independant ifs, and it will work as you expects, because it seems if you do:

    1. sqs = sqs.models(Things)
    2. sqs = sqs.models(Stuff)

    Will be the same as sqs.models(Things, Stuff)