Jasper
Jasper

Reputation: 2231

Django Q object AND operation not working

I have a listview of people with a filter. The filter has the following code:

    if textquery:
        qs = qs.filter()

        qs = qs.filter(Q(name__icontains=textquery) |
                       Q(surname__icontains=textquery) |
                       Q(surname__icontains=textquery) & Q(name__icontains=textquery)
                       )


    return qs

People can have both a first and a last name, and searching for those works as expected. However, when I input both the first AND the lastname, the program does not return any results (even though I thought that the '&' operation in the end should include both variables).

In summary: this is currently the result of my queries:

Person: 'John Doe' 
Query:  'John' 
Result: 'John Doe' 

Person: 'John Doe' 
Query: 'Doe'
Result: 'John Doe'

Person 'John Doe'
Query: 'Johh Doe'
Result: ''

Does anyone know what I am doing wrong, and why matches for both the NAME and SURNAME do not return any results?

Upvotes: 1

Views: 680

Answers (3)

Du D.
Du D.

Reputation: 5310

@neverwalkaloner has it right. You can use their solution or try this one below, it combines the name and surname together and make the solution more flexible. So now if even the textquery is "n D" it still matches.

from django.db.models.functions import Concat
from django.db.models import F, Value

qs = qs.annotate(fullname=Concat(F('name'), Value(' '), F('surname')))\
            .filter(fullname__icontains=textquery)

Upvotes: 2

Sumeet Kumar
Sumeet Kumar

Reputation: 1019

Your query is working fine.

Person: 'John Doe' 
Query:  'John Doe' 
Result: '' 

is also correct. Try to understand. John Doe neither match with John nor with Doe.

Upvotes: 0

neverwalkaloner
neverwalkaloner

Reputation: 47364

The filter returns nothing because current code check if firstname or lastname contain FULL name. This will return False everytime. E.g. John is not contains John Doe. So you need to parse textquery as name and surname:

if textquery:
    qs = qs.filter()
    name, surname = textquery.split()
    qs = qs.filter(Q(name__icontains=textquery) |
                   Q(surname__icontains=textquery) |
                   Q(surname__icontains=name) & Q(name__icontains=surname)
                   )

Upvotes: 3

Related Questions