TAGS :Viewed: 2 - Published at: a few seconds ago

[ Filter multiple keywords ]

I am trying to make a search refiner on my website which filters keywords, the problem is that sometimes people may want to search multiple keywords. The problem is by default if they entered "hello world" it would search for that exact phrase however I want it to separate it so that it searches for "hello" and "world". So far I have added .split() to the keywords and that did divide it however it prevented me from using __icontains in the query. Could anyone suggest the best way to do this? Cheers!

Code -

def browse(request):

    business_industry = request.GET.get('business_industry', '')
    business_address_region = request.GET.get('business_address_region', '')
    employment_type = request.GET.get('employment_type', '')
    pay_rate = request.GET.get('pay_rate', '')
    keywords = request.GET.get('keywords', '').split()

    form = JobSearchForm(initial=request.GET)

    filters = Q(active_listing=True)

    if business_industry:
        filters &= Q(business_industry=business_industry)
    if business_address_region:
        filters &= Q(business_address_region=business_address_region)
    if employment_type:
        filters &= Q(employment_type=employment_type)
    if pay_rate:
        filters &= Q(pay_rate=pay_rate)
    if keywords:
        filters &= Q(job_description__icontains=keywords) | Q(job_title__icontains=keywords)

    job_listings = JobListing.objects.filter(filters).distinct().order_by('-listing_date')

    context_dict = {
        'joblistings': job_listings,
        'form': form
    }

    return render(request, 'browse.html', context_dict)

Edit: I have been asked to explain why this post is unique, the other question is asking how to compare his query to all his model fields. This is asking how to filter multiple keywords from a single field.

Answer 1


You can make the query in a loop over keywords:

job_description_q = Q()
for keyword in keywords:
    job_description_q |= Q(job_description__icontains=keyword)
filters &= job_description_q 

And a similar loop for jobtitle.

Answer 2


You might need to use iteration for this

keyword_filter = Q()
for keyword in keywords:
   keyword_filter|=Q(job_description__icontains=keyword) | Q(job_title__icontains=keyword)
filters &= keyword_filter

You can take a look at this similar question http://stackoverflow.com/a/5956422/2599266

Answer 3


You can use Reduce function :

reduce(lambda x, y: x | y, [Q(name__icontains=word) for word in list])

Change this code :

if keywords:
    filters &= Q(job_description__icontains=keywords) | Q(job_title__icontains=keywords)

To :

if keywords:
    fliters &= reduce(lambda x, y: x | y, [Q(job_description__icontains=word) for word in keywords]) | reduce(lambda x, y: x | y, [Q(job_title__icontains=word) for word in keywords])

you can change lambda definition as you like. For example if you want to find listings which have all of the keywords, replace lambda x, y: x | y with lambda x, y: x & y.

Edit: Modified code as there were two unnecessary brackets

Answer 4


filters = {'active_listing':True}
q = Q()

if business_industry:
    filters['business_industry'] = business_industry
if business_address_region:
    filters['business_address_region'] = business_address_region
if employment_type:
    filters['employment_type'] = employment_type
if pay_rate:
    filters['pay_rate'] = pay_rate
if keywords:
    q = Q(job_description__icontains=keywords) | Q(job_title__icontains=keywords)

job_listings = JobListing.objects.filter(q, **filters).distinct().order_by('-listing_date')