I am trying to construct a complex query in Django by adding Q objects based on a list of user inputs:
from django.db.models import Q
q = Q()
expressions = [
{'operator': 'or', 'field': 'f1', 'value': 1},
{'operator': 'or', 'field': 'f2', 'value': 2},
{'operator': 'and', 'field': 'f3', 'value': 3},
{'operator': 'or', 'field': 'f4', 'value': 4},
]
for item in expressions:
if item['operator'] == 'and':
q.add(Q(**{item['field']:item['value']}), Q.AND )
elif item['operator'] == 'or':
q.add(Q(**{item['field']:item['value']}), Q.OR )
Based on this I am expecting to get a query with the following where condition:
f1 = 1 or f2 = 2 and f3 = 3 or f4 = 4
which, based on the default operator precedence will be executed as
f1 = 1 or (f2 = 2 and f3 = 3) or f4 = 4
however, I am getting the following query:
((f1 = 1 or f2 = 2) and f3 = 3) or f4 = 4
It looks like the Q() object forces the conditions to be evaluated in the order they were added.
Is there a way that I can keep the default SQL precedence? Basically I want to tell the ORM not to add parenthesis in my conditions.