13Aug

Dynamic OR’d Queryset creation with Django

Posted by Elf Sternberg as Uncategorized

For multi-select boxes where you have a list of things you want to filter on, and you want the queryset returned to be an OR’d set.

    qset = Q(mode__exact=modes[0])
    if len(modes) > 1:
        for mode in modes[1:]:
           qset = qset | Q(mode__exact=mode)
    r = Responses.objects.filter(qset)

Now, I need to figure out how to do this as a list comprehension!

For extra coolness, you can see what SQL you’re generating:

    print r.query.as_sql()

10 Responses to Dynamic OR’d Queryset creation with Django

Travis Cline

August 13th, 2009 at 9:33 pm

A slight golfing:

qset = Q()
for mode in modes:
qset |= Q(mode=mode)
r = Responses.objects.filter(qset)

or:

r = Responses.objects.filter(reduce(lambda x,y: x|Q(mode=y), modes, Q()))

But that’s probably getting too clever.

Ryan

August 14th, 2009 at 2:28 am

You could start off with qset = Q(), and then loop through all the modes, OR’ing them together, without having to check the length.

Bartek

August 14th, 2009 at 7:14 am

To make it a list comprehension you can try something like this:

import operator

qset = reduce(operator.__or__, [Q(mode__exact=mode) for mode in modes[1:]])

Didn’t test it, but it should work. Perhaps it can even be improved :)

Andre LeBlanc

August 14th, 2009 at 8:10 am

I’m about 90% sure that

qset = Responses.objects.filter(mode__in=modes)

would have the exact same effect.

also, naming a model after the plural form of the word is considered bad form. the model really should be called “Response” but thats just nitpicking.

Brian Luft

August 14th, 2009 at 9:15 am

While OR’ing Q objects together can be useful in some scenarios (may not scale well), why didn’t you use something like:

Responses.objects.filter(mode__in=modes)

Elf Sternberg

August 14th, 2009 at 9:47 am

Brian, that’s useful under most circumstances, but in actual usage, I was getting querysets generated from multiple, sometimes remote, sources, and needed them OR’d together for the final result. The snippet I posted was simply for illustrative purposes.

Elf Sternberg

August 14th, 2009 at 9:49 am

Andre, yes, I know about the plural vs. singular. It’s correct in the production code; I slipped making the example. And as I pointed out to Brian, in the production code multiple remote applications are being sent requests for querysets that need to be OR’d for the final production. Would it work correctly for, say, “contains” as the argument? (There’s a lot of text string searching going on.)

fayce

November 7th, 2009 at 12:41 pm

Thank you for this post ! all thoses answers were helpful to me and really instructive… but I still can find how I can apply it to my problem even if it’s really similar.

Everything is dynamic in my queryset:
- the logical operator ( | or &)
- the operator (lte, gte, icontains ….)
- the name of the field (what you call the mode?)
- and the value…

I would like to build the complete queryset from strings, like this:

tab =
[['field1','value1','operator1','logical-operator1'],
['field2','value2','operator2','logical-operator2'],
['field3','value3','operator3','logical-operator3']
]

for e in tab:
req = req e[3] Q(e[0]__e[2]=e[1])

r = Obj.Objects.filter(req)

I know this is completely wrong and will never work.. but this is the idea..

Thank you for you help !

fayce

November 7th, 2009 at 3:54 pm

I found the solution ! and it works !!

I had to combine Travis Cline method and some dicts and everything works just fine…

So, if someone is interested to know more about how I did, feel free to ask.

Dynamic OR’d Queryset Creation with Django « SRA Lab

January 27th, 2011 at 6:22 am

[...] complete posts and comments published on Elf Sternberg's blog, this is the method I found to create dynamic complex queryset with Django (Q and [...]

Comment Form

Recent Comments