I have a search bar that is searching in 2 models columns title, body, short_description. I am.using MySQL database. Right now, I am using Q lookups but there are some search limitations that I'd like to 'improve'.
One of them is that Q lookups find only results based only on phrase results that are exactly the same as in field so for instance, I have the title why python is so amazing?
and I must write why
or python
or python is
in order to get results. What I'd like to get is to extend the search bar to work in the following way:
A user inserts a question in the search bar: python language
and search lookup is splitting each word and returning all objects that contain python
or language
. In the end the result would return object with why python is so amazing?
, no matter it user puts python language
or amazing python
.
I am posting my current code below:
views.py
def search_items(request):
query = request.GET.get('q')
article_list= Article.objects.filter(title__icontains=query)
qa_list = QA.objects.filter(title__icontains=query)
if query is not None:
lookups = Q(title__icontains=query) | Q(short_description__icontains=query) | Q(body__icontains=query)
article_list= Article.objects.filter(lookups, status=1).distinct()
qa_list = QA.objects.filter(lookups, status=1).distinct()
context = {
'query_name': query,
'article_list': article_list,
'qa_list': qa_list,
}
return render(request, 'search/search_items.html', context)
I've checked this solution and this one but the results are not satisfactory because when I put python language
to find an object with the title why python is so amazing
I get no result.
Question
I'd appreciate any advice on how to achieve the result where I get objects with a list of all objects based on words that the user puts into the input field.
I ran into the same issue, and solved it by adding a custom search manager in models.py, above my model. The manager has two methods, one for single word searches, another for multi-word. The query string is split into a list of words using the
.split()
, (see the view) below.models.py
and of course, declare the custom manager below your model fields:
Then, in your view, split the search string and distinguish between single word searches and multi-word searches:
For multi-word strings, the magic is in the
reduce
function that attempts all keywords against the given model fields. Much of the credit for this manager pattern goes to Justin Mitchel's excellent writeup on multi-model search.