python-3.xdjangodjango-q

Django Q: build dynamic query from array


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}')")

Solution

  • 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!