21

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.

3 Answers 3

14

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
Sign up to request clarification or add additional context in comments.

2 Comments

why not args |= each_args?
Thanks for suggestion. I will write enhance this answer. :)
13

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.

1 Comment

on a side note, reduce is now functools.reduce in Python 3 docs.python.org/3.0/library/functools.html#functools.reduce
1
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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.