Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Constructing Django filter queries dynamically with args and kwargs

Tags:

I'm constructing some Django filter queries dynamically, using this example:

kwargs = { 'deleted_datetime__isnull': True }
args = ( Q( title__icontains = 'Foo' ) | Q( title__icontains = 'Bar' ) )
entries = Entry.objects.filter( *args, **kwargs )

I'm just not sure how to construct the entry for args. Say I have this array:

strings = ['Foo', 'Bar']

How do I get from there to:

args = ( Q( title__icontains = 'Foo' ) | Q( title__icontains = 'Bar' ) 

The closest I can get is:

for s in strings:
    q_construct = Q( title__icontains = %s) % s
    args.append(s)

But I don't know how to set up the | condition.

like image 605
Richard Avatar asked Dec 14 '11 18:12

Richard


3 Answers

you have list of Q class objects,

args_list = [Q1,Q2,Q3]   # Q1 = Q(title__icontains='Foo') or Q1 = Q(**{'title':'value'})   args = Q()  #defining args as empty Q class object to handle empty args_list for each_args in args_list :     args = args | each_args  query_set= query_set.filter(*(args,) ) # will excute, query_set.filter(Q1 | Q2 | Q3) # comma , in last after args is mandatory to pass as args here 
like image 131
Roshan Avatar answered Nov 18 '22 05:11

Roshan


You can iterate it directly using a kwarg format (I don't know the proper term)

argument_list = [] #keep this blank, just decalring it for later fields = ('title') #any fields in your model you'd like to search against query_string = 'Foo Bar' #search terms, you'll probably populate this from some source  for query in query_string.split(' '):  #breaks query_string into 'Foo' and 'Bar'     for field in fields:         argument_list.append( Q(**{field+'__icontains':query_object} ) )   query = Entry.objects.filter( reduce(operator.or_, argument_list) )  # --UPDATE-- here's an args example for completeness  order = ['publish_date','title'] #create a list, possibly from GET or POST data ordered_query = query.order_by(*orders()) # Yay, you're ordered now! 

This will look for each string in your query_string in each field in fields and OR the result

I wish I still had my original source for this, but this is adapted from code I use.

like image 20
j_syk Avatar answered Nov 18 '22 06:11

j_syk


firstQ = [
    Q(...),
    Q(...),
    Q(...)
]
import functools
functools.reduce(lambda a, b: a & b, Qrelationship)

Or in my case, I needed to AND to different sets of filters:

firstQ = [
    Q(...),
    Q(...),
    Q(...)
]
secondQ = [
    Q(...),
    Q(...),
    Q(...)
]
import functools
combined = functools.reduce(lambda a, b: a | b, [
    functools.reduce(lambda a, b: a & b, firstQ),
    functools.reduce(lambda a, b: a & b, secondQ)
])
myqueryset = Model.objects.filter(combined)
# Make sure you apply the Q's first (BEFORE any other filter) or it will fail silently
like image 20
Ryan Avatar answered Nov 18 '22 05:11

Ryan