I try to combine AND and OR in a filter using Q objects. It looks like that the | behave like an AND. This is related to the previous annotate which is run in the same query and
Here's my example of complicated query, I hope you find it helpful
or_condition = Q()
and_condition = Q(company=request.user.profile.company)
for field in MyModel._meta.get_fields():
if field.name != 'created_on' and field.name != 'company':
or_condition.add(
Q(**{"{}__icontains".format(field.name): query}), Q.OR)
and_condition.add(or_condition2, Q.AND)
MyModel.objects.filter(and_condition)
The problem with this method is that you get an empty (AND: )
case in your or_condition
. It doesn't affect the query at all, but it annoys me!
My current solution is as follows
import operator
from functools import reduce
and_condition = Q(company=request.user.profile.company)
or_condition = reduce(operator.or_, (Q(**{"{}__icontains".format(field.name): query})
for field in MyModel._meta.get_fields() if field.name != 'created_on' and field.name != 'company'))
and_condition.add(or_condition, Q.AND)
MyModel.objects.filter(and_condition)