The Bearded Templar
The Bearded Templar

Reputation: 701

Filtering Django queryset with custom function

I'm developing a REST API for an existing system that uses custom permission handling. I'm attempting to use the built-in generics from the Django REST Framework, but I'm running into trouble filtering the list views using my custom permissions. An example of my current view is:

class WidgetList(generics.ListCreateAPIView):
    permission_classes = (permissions.IsAuthenticated,)
    model = Widget
    serializer_class = WidgetSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('widget_type', 'widget_owner')

    def get_queryset(self):
        """
        Overwrite the query set to check permissions
        """
        qs_list = [w.id for w in self.model.objects.all() if
                   canReadWidget(self.request.user, w)]
        return self.model.objects.filter(id__in=qs_list)

This works, however I feel like the get_queryset function could be improved. Because my canReadWidget is custom, I have to evaluate self.model.objects.all() and check which widgets the user can read, but the function must return a query set so I use the id__in=qs_list part. The result being that I make two database calls for what is really just one list fetch.

Is there a standard way to handle this kind of per-object filtering for a generic list view?

Upvotes: 2

Views: 921

Answers (2)

AddWeb Solution Pvt Ltd
AddWeb Solution Pvt Ltd

Reputation: 21681

first install django-filter package and register in settings.py

Write this code on filter.py file

import django_filters
from .models import CustomUser


class UserFilter(django_filters.FilterSet):
    first_name = django_filters.CharFilter(label="First Name", lookup_expr='icontains')
    last_name = django_filters.CharFilter(label="Last Name", lookup_expr='icontains')
    email = django_filters.CharFilter(label="Email", lookup_expr='icontains')
    mobile_number = django_filters.CharFilter(label="Mobile No.", lookup_expr='icontains')
   ##Change Your Fields What You Want To Filtering
    
    class Meta:
        model = Widget
        fields = {'is_verify'}

On Your Views File write this code:

class WidgetViewSet(MyModelViewSet):
    queryset = Widget.objects
    serializer_class = "pass your serializer"

    def get_filter_data(self):
        _data = self.queryset.all()
        data = UserFilter(self.request.GET, queryset=_data)
        return data.qs.order_by('-id')

    def get_queryset(self):
        return self.get_filter_data()

Upvotes: 0

Linovia
Linovia

Reputation: 20956

At some point, it's better to drop the default generic views or function and roll your own.

You should have a look at the ListModelMixin and override the list to deal with the list instead of turning it into a queryset.

You should adapt the filtering and pagination but you won't hit the DB twice as you currently do.

Upvotes: 1

Related Questions