Reputation: 4461
Django 1.10.1
Search form. The user inserts words separated by spaces. Necessary to find objects with ANY of these words in the title field.
I'm planning to use something like this:
Article.objects.filter(
Q(title__icontains="table") | Q(title__icontains="helm")
)
I can make Q objects easily: q = Q(title__icontains="table").
But the obstacle is how to pass arguments to the filter method.
https://docs.djangoproject.com/en/1.10/topics/db/queries/
The syntax is filter(**kwargs).
With a loop I can prepare a dictionary like this :
q_objects = {"1": Q(title__icontains="table"), "2": Q(title__icontains="glasses")}
But the problem is with that "|".
How to pass it to the filter method is a mystery to me. In other words I fail to build a filter with OR logical operator.
Could you help me?
Upvotes: 1
Views: 555
Reputation: 21
In the same line as proposed by @Todor and based on this post, I like this syntax better:
reduce(operator.or_, (Q(title__icontains=x) for x in ['x', 'y', 'z']))
The full code with your example could be:
list_of_words = ['table', 'helm'] # words wanted by the user
Article.objects.filter(
reduce(operator.or_, (Q(title__icontains=word) for word in list_of_words))
)
Upvotes: 1
Reputation: 7787
query = Q()
for word in words:
query |= Q(title__icontains=word)
Article.objects.filter(query)
or
from operator import __or__ as OR
from functools import reduce
query = [Q(title__icontains=word) for word in words]
Article.objects.filter(reduce(OR, query))
Upvotes: 3
Reputation: 16020
You can do something like this:
queryset = MyModel.objects.all()
queries = ['table, helm']
filter_ = 'title__icontains'
queryset.filter(reduce(lambda q1,q2: q1|q2, [Q(**{filter_: q}) for q in queries], Q()))
#This will build a QuerySet similar to this one:
queryset.filter(Q(title__icontains='table')|Q(title__icontains='helm'))
Upvotes: 1