Vaibhav Jain
Vaibhav Jain

Reputation: 5507

How to do complex query like this

I have the following get and get_queryset methods in my CustomersListView class:

def get(self, request, *args, **kwargs):
    """
    :param request:
    :param args:
    :param kwargs:
    :return:
    """


    self.id = request.GET.get('id')
    self.f_name = request.GET.get('f_name')
    self.m_name = request.GET.get('m_name')
    self.l_name = request.GET.get('l_name')
    self.r_name = request.GET.get('r_name')
    self.p_no = request.GET.get('p_no')
    self.gender = request.GET.get('gender')


    return super(CustomersListView, self).get(request, *args, **kwargs)

def get_queryset(self):
    """
    :return:
    """

    query_list = [Q(id=self.id), Q(first_name__contains=self.f_name), Q(middle_name__contains=self.m_name),
                  Q(last_name__contains=self.l_name), Q(relative_name__contains=self.r_name),
                  Q(phone_no_1__contains=self.p_no), Q(phone_no_2__contains=self.p_no), Q(gender=self.gender),
                  ]

    return Customer.objects.filter(reduce(operator.and_, query_list))

User can submit data in following ways:

1: If user submits empty form then all the entries of the Customer model should be returned.

2: If user submits data in any one field then data should be filtered according to that field.

3: If user submits data in more then one field then query should filter data according to both field i mean(and).

Note: request.GET.get() will return u'' for the empty form fields. And id should be integer for searching customer model by id not by unicode string u''.

For example :

>>> Customer.objects.filter(Q(id=None) and Q(first_name__contains='Secon') and Q (last_name__contains=''))

[<Customer: vaibhav kumar jain >, <Customer: second customer second customer second customer >]

But i want results corresponding to only Q(first_name__contains='Secon') lookup which is

<Customer: second customer second customer second customer > not

[<Customer: vaibhav kumar jain >, <Customer: second customer second customer second customer >]

Upvotes: 0

Views: 76

Answers (1)

danielcorreia
danielcorreia

Reputation: 2136

You can do this with keyword arguments and some filtering:

def get_queryset(self):
    # filters_map keys must match your queries
    filters_map = {
        'id': self.request.GET.get('id'),
        'first_name__icontains': self.request.GET.get('f_name'),
        'middle_name__icontains': self.request.GET.get('m_name'),
        'last_name__icontains': self.request.GET.get('l_name'),
        'relative_name__icontains': self.request.GET.get('r_name'),
        'phone_no_1__contains': self.request.GET.get('p_no'),
        'phone_no_2__contains': self.request.GET.get('p_no'),
        'gender': self.request.GET.get('gender')
    }
    # leave out empty strings
    query = dict((key, value) for key, value in filters_map.iteritems() if value)

    return Customer.objects.filter(**query)

A bit more about keyword arguments.

PS: I think it makes more sense to filter the queryset in the get_queryset method.

Upvotes: 1

Related Questions