Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django Building a queryset with Q objects

I have a form that allows you to pick multiple project types to filter from. For instance, say you have the project types "Research", "Training", and "Evaluation".

Basically what I'm looking to do is build a queryset using Q objects like:

projects.filter(Q(type__type="Research") | Q(type__type="Training"))

I'm just not sure how to build this without the filter() input being a string, which produces an error:

querystring = ""
for t in types:
    querystring += " | Q(type__type="+t+")"
projects.filter(querystring) ## produces error: "ValueError: too many values to unpack"

So what would be a way to iterate over the types to create a queryset with Q objects?

like image 263
richard008 Avatar asked Nov 26 '13 16:11

richard008


People also ask

What is Q objects in Django?

Q object encapsulates a SQL expression in a Python object that can be used in database-related operations. Using Q objects we can make complex queries with less and simple code. For example, this Q object filters whether the question starts wiht 'what': from django.

Is Django QuerySet lazy?

This is because a Django QuerySet is a lazy object. It contains all of the information it needs to populate itself from the database, but will not actually do so until the information is needed.

How does Django define QuerySet?

A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.


1 Answers

You are just building a string with no relationship to actual Q() query objects; start with the first Q() instance and add more:

query = Q(type__type=types[0])
for t in types[1:]:
    query |= Q(type__type=t)
projects.filter(query)

You could also use the functools.reduce() function to do this:

from functools import reduce
from operator import or_

query = reduce(or_, (Q(type__type=t) for t in types))
projects.filter(query)

The reduce() call does exactly the same thing as the for loop above; take a series of Q(..) objects and combine them into a larger query with all the parts combined with | or operations.

like image 177
Martijn Pieters Avatar answered Oct 03 '22 23:10

Martijn Pieters