Django: How to use a string as a keyword in a Q () statement?

I am writing a simple search form for a specific model. Let me name the Orchard model and give it the apples , oranges and pears for demonstration only.

Thus, the form does not require filling all the fields. So you can search for apples and oranges , but not pears. I 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 empty, results are never returned.

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 occurs in the marked lines. I obviously can’t just use the β€œkey” as the attribute keyword, because it does not accept a string, it takes essentially a variable.

So ... how do I get around this?

If there is a known solution to this problem that does not include Q That would also be helpful.

+6
source share
2 answers

This is a common problem with using a variable as a keyword in the arg keyword. the solution is to wrap things in a dict and unzip 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) 
+9
source

@ The second answer is correct, unzip the dictionary using the ** operator to provide keyword arguments.

However, if you use only AND to combine Q objects, not OR, you don't actually need to use Q objects in your example. Just create a search dictionary and then use it as 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) 
0
source

Source: https://habr.com/ru/post/901575/


All Articles