1

For a Django project, I have a dictionary which contains the model name and the columns where to look for. So what I want to achieve is to build the query from the variables coming from my dictionary.

        sq = []
        for x in columns:
            print(x)
            sq.append(f'Q({x}__icontains=val)')
        print(sq)
        query = (' | '.join(sq))
        print(query)

        lookups = Q(name__icontains=val) | Q(code__icontains=val)
       # lookups = query

When I do the above, it correctly builds the "string" representing the query, but I'm unable to use it.

The error is as follows:

Traceback (most recent call last):   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)   File "/home/user/price_engine/masterdata/views.py", line 50, in search_form
    results = Plant.objects.filter(query).distinct()   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/db/models/manager.py", line 87, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/db/models/query.py", line 1436, in filter
    return self._filter_or_exclude(False, args, kwargs)   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/db/models/query.py", line 1454, in _filter_or_exclude
    clone._filter_or_exclude_inplace(negate, args, kwargs)   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/db/models/query.py", line 1461, in _filter_or_exclude_inplace
    self._query.add_q(Q(*args, **kwargs))   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1534, in add_q
    clause, _ = self._add_q(q_object, self.used_aliases)   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1565, in _add_q
    child_clause, needed_inner = self.build_filter(   File "/home/user/price_engine/env/lib/python3.9/site-packages/django/db/models/sql/query.py", line 1412, in build_filter
    arg, value = filter_expr ValueError: too many values to unpack (expected 2) [05/Jul/2023 04:27:27] "POST /master/search/plant HTTP/1.1" 500 97494

What am I overlooking? Or am I trying to achieve something in a stupid way?

Basically I want to build the query from a a set of variables, derived from a dictionary based on a single string value (representing the key).

Edit: I think it should be rather as follows, but still the same issue (overlooked the {val}:

sq.append(f"Q({x}__icontains='{val}')")
Berik
  • 65
  • 4

2 Answers2

2

you can pass unpacked dictionary to Q object.

so, create dictionary then pass Q object. like this.

filter_q = Q()
for x in columns:
    filter_q |= Q(**{f'{x}__icontains': val}  # '|' means as you know 'OR'

then using q.

somequeryset.filter(filter_q)

additional

Q object can choose connector ('OR' or 'AND')

like this.

Q(foo__icontains='bar', zoo__icontains='bar', _connector=Q.OR)

which means (default _connector is 'AND', see this -https://stackoverflow.com/a/58145006/19176724)

Q(foo_icontains='bar') | Q(foo__icontains='bar')

good luck!

Hovak
  • 36
  • 4
  • Awesome. Thank you for you response. Would this also allow for a method to change the Model based of a variable? – Berik Jul 05 '23 at 06:20
  • Getting the model also solved: https://stackoverflow.com/questions/4881607/django-get-model-from-string/26126935#26126935 – Berik Jul 05 '23 at 06:51
  • Sorry for the late reply. I saw the link, That's exactly what I know. Glad it helped anyway :) – Hovak Jul 05 '23 at 07:59
1

Before passing it into filter, you need to convert it into correct Q objects, try evaluating the query:

query = eval(query)
results = Plant.objects.filter(query).distinct()
Ersain
  • 1,466
  • 1
  • 9
  • 20
  • Thank you very much for this. It indeed works as intended! I only understood using eval() is not allways recommended due to a security risk? – Berik Jul 05 '23 at 06:19