Tsuna
Tsuna

Reputation: 2198

Is there a better way to make this queryset using Q? django

I have a query which uses filter but I know there is this thing called Q but trying to play around with it, I am not sure how I can use Q. I am not sure which one would be better but trying to know another way to do the query.

What I actually want to do is... for my queryset return I have a default field and two input fields which are options.

let's say, language in default is english, there is a location and title field. If location and title fields are available, make a query to query location, title, and language. If only location then only query location and language, if only title then only query title and language.

I have done it two ways, one with filter only which has less code...

    postings = Posting.objects.filter(language='EN')
    if kwargs.get('title'):
        postings = postings.filter(title__icontains=kwargs.get('title'))
    if kwargs.get('location'):
        postings = postings.filter(location__icontains=kwargs.get('location'))

the above does work with using only filter

I am trying to see if I can do it with using Q but cannot seem to make it work

I have something like this at the moment

    if title and location:
        postings = Posting.objects.filter(title__icontains=title, location__icontains=location, language='EN')
    else:
        queryQ = Q(posting_language='EN')
        if title:
            queryQ |= Q(title__icontains=title)
        if location:
            queryQ |= Q(location__icontains=location)

        postings = Posting.objects.filter(queryQ)

can someone please give me a hand? Thanks in advance

Upvotes: 0

Views: 622

Answers (2)

Alasdair
Alasdair

Reputation: 308779

Firstly, | is for ORing Q objects. You want & for ANDing them.

You could rewrite your filter code as:

queryQ = Q(posting_language='EN')
if title:
    queryQ &= Q(title__icontains=title)
if location:
    queryQ &= Q(location__icontains=location)

postings = Posting.objects.filter(queryQ)

However I don't see any real advantage of this. Personally I think your original code is more readable.

Upvotes: 4

Asher
Asher

Reputation: 697

I think you've misunderstood what Q is for. Q is mostly used in django for more complex query statements that require OR/AND.

So, you could do something like this:

postings = Posting.objects.filter(Q(title__icontain=title) | Q(location=location))

This will give you all the postings where title contains the title OR the location contains the location. It's not very useful in this context because icontains will fail with a Null value and return everything for an empty string value.

Q would be very useful if you needed postings for titles that used two different icontains

postings = Posting.objects.filter(Q(title__icontains=search_term_a) & Q(title__icontains=search_term_b))

Upvotes: 0

Related Questions