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

假如想象 提交于 2020-01-24 02:51:49

问题


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.


回答1:


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)



回答2:


@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)


来源:https://stackoverflow.com/questions/8144582/django-how-do-i-use-a-string-as-the-keyword-in-a-q-statement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!