Rodriguez David
Rodriguez David

Reputation: 571

django Q objects ValueError: too many values to unpack (expected 2)

I am trying to build Q objects dynamically. This is my code:

class StudentiRicerche(ListAPIView):

    serializer_class = StudentiLista

    def get_queryset(self):

        query_params = self.request.query_params

        q_objects = Q()
        for k, v in query_params.items():
            param = '{0}__icontains={1}'.format(k, v) # k and v are dynamic values
            q_objects &= Q(param)

        queryset = Studenti.objects.filter(q_objects) # Here i get an error
        return queryset

With this code I am getting a ValueError on the line where I use filter

I have also tried to use a list of Q objects insted of Q objects directly in this way:

class StudentiRicerche(ListAPIView):

    serializer_class = StudentiLista

    def get_queryset(self):

        query_params = self.request.query_params
        q_list = []

        for k, v in query_params.items():
            param = '{0}__icontains={1}'.format(k, v)
            q_list.append(Q(param)) # Q with 'and' condition

        queryset = Studenti.objects.filter(*q_list) # here I get an error also
        return queryset

But here I am getting again the same error! Any idea??

Upvotes: 0

Views: 608

Answers (1)

Quazer
Quazer

Reputation: 383

Simplify. You don't need use Q:

class StudentiRicerche(ListAPIView):

    serializer_class = StudentiLista

    def get_queryset(self):

        query_params = self.request.query_params
        queryset = Studenti.objects.filter(**{'{}__icontains'.format(k):v for k,v in query_params.items() })
        return queryset

Explain:

  1. Arguments of .filter and Q() is dictionary, not list
  2. .filter and Q() use named-arguments, such as: .filter(name__icontains='Ivan', email__icontains='mail.com')
  3. But you can use **kwargs: .filter(**{'name__icontains':'Ivan', 'email__icontains': 'mail.com')
  4. For you example: .filter(**{'{}__icontains'.format(k):v for k,v in query_params.items() })
  5. If you want Q() dynamically you must use dictionary: Q(**{'{}__icontains'.format(k):v for k,v in query_params.items() })

and in addition

  1. You can use combination of named-arguments and **kwargs, such as .filter(is_active__isnull=False, **{'{}__icontains'.format(k):v for k,v in query_params.items() })

Upvotes: 2

Related Questions