I'm looking to create a slightly more complex query that is written fairly easily using raw SQL. Here's an example of the query in raw:
SELECT my,fields FROM sales WHERE is_paid = False OR status = 'toship' AND otherfield = 'FOO' AND anotherfield = 'BAR'
This is simple, it generates all the results that are is_paid = False and then a second result set for my AND matches.
Now I know about Q objects, I know about filtering but I can't seem to wrap my mind around how to achieve this in the Django ORM cleanly.
Any tips?
Thanks
You can keep building your Q object in a somewhat dynamic fashion.
Example:
query1 = Q(is_paid=False)
query2 = Q()
if status:
query2 = Q(status=status)
if otherfield:
query2 = query2 & Q(otherfield=otherfield)
if anotherfield:
query2 = query2 & Q(anotherfield=anotherfield)
query = query1 | query2
result = model.objects.filter(query)
Although googletorp is right that you can't construct the query dynamically with a string, you can do it with dictionary parameters. Something like:
model.objects.filter(Q(**mydict1) | Q(**mydict2))
where mydict1 and 2 are of the form:
{'field1': 'value1'}
{'field2__icontains': 'value2'}
etc.
Something like this should work:
model.objects.filter(Q(is_paid=False) | Q(status='toship', otherfield='FOO', anotherfield='BAR'))
Edit:
You can't create the query dynamically the same way you can construct a string containing a SQL statement to be executed when completed. If you want to do this, I would suggest using an if state, function or what suits your use case best:
if query == 'simple':
result = model.objects.filter(Q(is_paid=False))
else:
result = model.objects.filter(Q(is_paid=False) | Q(status='toship', otherfield='FOO', anotherfield='BAR'))
for items in result:
...
This could be more complex, but I'm sure you get the idea.
This is a great way to do dynamic "OR" querying:
import operator
from django.db.models import Q
from your_app.models import your_model_object
q_list = [Q(question__startswith='Who'), Q(question__startswith='What')]
your_model_object.objects.filter(reduce(operator.or_, q_list))
if you want to use "AND":
your_model_object.objects.filter(reduce(operator.and_, q_list))