Ali
Ali

Reputation: 2591

Filtering with multi field in django orm

I have some fields that I can use them for filtering a list. I can use all of this fields or some of them in filter query. MY view is like below. But I can not get a right answer. It means that some records that I expect to have been selected are not selected.

class UserListAPIView(ListAPIView):

serializer_class = serializers.UserListSerializer
pagination_class = AdminPagination
permission_classes = (IsAuthRolePermission,)

filter_backends = (filters.OrderingFilter,)
ordering_fields = '__all__'


def get_queryset(self):

    full_name     = self.request.query_params.get('full_name', '')
    email         = self.request.query_params.get('email', '')
    facility_name = self.request.query_params.get('facility_name', '')
    user_state    = self.request.query_params.get('user_state', '')

    if full_name or email or facility_name or user_state:

        queryset = User.objects.filter(full_name__icontains=full_name,
                                       email__icontains=email,
                                       facility_name__icontains=facility_name,
                                       user_state__icontains=user_state) \
            .annotate(facility=F('facility_name'),
                      state=F('user_state'),
                      last_access=F('lastAccess')) \
            .order_by('-id').distinct()

    else:
        queryset = User.objects.all()\
            .annotate(facility=F('facility_name'),
                      state=F('user_state'),
                      last_access=F('lastAccess'))\
            .order_by('-id')

    return queryset

Upvotes: 0

Views: 208

Answers (1)

Ken4scholars
Ken4scholars

Reputation: 6296

You're doing it the wrong way. First, let me advice that such filtering should be done in the filter_queryset method and not get_queryset method or better off, use the DjangoFilterBackend from django-filter which is the common practice.

Now pertaining your code, you add the filters even when they are not specified. Assuming the client has added the query param full_name=foo, your code goes on to add email="",facility_name="",user_state="" to the filter which will most likely not return anything as there will be no combination of those values in the database. So rather, than doing that, add only the query params specified.

Something like this:

def get_queryset(self):

    filter_fields = ['full_name', 'email', 'facility_name', 'user_state']

    params = {'{}__icontains'.format(k): v for k,v in self.request.query_params.items() if k in filter_fields}

    queryset = User.objects.filter(**params) \
                .annotate(facility=F('facility_name'),
                          state=F('user_state'),
                          last_access=F('lastAccess')) \
                .order_by('-id').distinct()

    return queryset

Again, you should consider moving this to filter_queryset as that is the method meant for filtering.

Upvotes: 1

Related Questions