2

I have a list of strings:

phrases_filter = json.loads(request.GET['phrases_filter'])
['xx', 'yy']

I need to lookup all phrases in db, that contain xx OR yy

I tried it like this:

Phrase.objects.filter(name__in phrases_filter)

But this gave me only phrases that have in name xx AND yy

1 Answer 1

2

We can unroll the list, and define a set of __contains predicate with or-logic:

from django.db.models import Q
from functools import reduce
from operator import or_

Phrase.objects.filter(
    reduce(or_, (Q(name__contains=e) for e in phrases_filter))
)

In the case of the given phrases_filter, we will generate something equivalent to:

Phrase.objects.filter(
    Q(name__contains='xx') | Q(name__contains='yy')
)

So reduce(..) will operate on a generator of Q(..) objects, here [Q(name__contains='xx'), Q(name__contains='yy')]. The reduce(..) works like what is known in functional programming as a "fold" (which is a special case of a catamorphism).

We thus will add or_s in between, resulting in Q(name__contains='xx') | Q(name__contains='yy'). This is an object that basically encodes a filter condition: it means that the name column should __contains the substring 'xx', or the substring 'yy'.

Note: in case you want to match case insensitive (so rows with XX, or Xx, or xX, or xx are all candidates), then replace __contains with __icontains.

EDIT: based on your comment, in case phrases_filter is empty, you want all rows to match, we can do this by using an if statement:

from django.db.models import Q
from functools import reduce
from operator import or_

queryset = Phrase.objects.all()
if phrases_filter:
    queryset = filter(
        reduce(or_, (Q(name__contains=e) for e in phrases_filter))
    )

So only in case phrases_filter contains at least on element, we perform a filtering.

Sign up to request clarification or add additional context in comments.

6 Comments

can you explain it line by line, I don't really understand how it works and what does this mean
and this phrases_filter also can be empty
@user2950593: in case it is empty, then what should happen? No matches, or all rows match?
all rows match=)
okay, seems to be working=) is this a preferebla way to do this task?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.