Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: How do I use a string as the keyword in a Q() statement?

I'm writing a simple search form for a certain model. Let's call the model Orchard and give it the attributes apples, oranges, and pears, just for the sake of demonstration.

So, the form does not require all fields to be filled. So you can search on apples and oranges but not pears. I them need to filter like this:

Orchard.objects.filter(apples=request.GET.get('apples'), oranges=request.GET.get('oranges'), pears=request.GET.get('pears'))

but if pears is empty, no results will ever return.

My first thought was to use Q objects, something like this:

from django.db.models import Q

options = {}
options['apples'] = request.GET.get('apples')
options['oranges'] = request.GET.get('oranges')
options['pears'] = request.GET.get('pears')

queries = None

for key in options:
    if options[key] != u'':
        if queries:
            queries &= Q(key=options[key]) # <=== problem here
        else:
            queries = Q(key=options[key])  # <=== same problem here

results = Orchard.objects.filter(queries)

The problem comes up in those marked lines. I obviously can't just use "key" as the attribute keyword, because it doesn't take a string, it takes essentially a variable.

So... how do I get around this?

Unless there's a known solution to this problem not involving Q. That would be helpful too.

like image 583
Ken Bellows Avatar asked Nov 15 '11 23:11

Ken Bellows


People also ask

What is F in Django QuerySet?

F() expressions. An F() object represents the value of a model field, transformed value of a model field, or annotated column. It makes it possible to refer to model field values and perform database operations using them without actually having to pull them out of the database into Python memory.

Does Django ORM support subquery?

¶ Django allows using SQL subqueries.

What is OuterRef?

`OuterRef` is an "outer reference", a construct created to allow a reference to the query surrounding the current subquery.

How do I join a query in Django?

Join QueriesJoin can be done with select_related method: Django defines this function as Returns a QuerySet that will “follow” foreign-key relationships, selecting additional related-object data when it executes its query.


2 Answers

this is a general issue with using a variable as the key in a keyword arg. the solution is to wrap things in a dict and unpack it:

queries &= Q(**{key: options[key]})

or in your case

for option in options:
    if options[option] is None:
        del(options[option])
# or otherwise only add the ones you actually want to filter on
# then
results = Orchard.objects.filter(**options)
like image 161
second Avatar answered Oct 26 '22 00:10

second


@second's answer is correct, unpack a dictionary with the ** operator to provide keyword arguments.

However, if you are only using AND to combine Q objects and not OR, then you don't actually need to use Q objects in your example. Just build a dictionary of the lookups, then use that as the keyword arguments for filter.

options = {}
for key in ('apples', 'oranges', 'pears'):
    value = request.GET.get(key)
    if value:
        options[key] = value
results = Orchard.objects.filter(**options)
like image 45
Alasdair Avatar answered Oct 25 '22 22:10

Alasdair