2

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?

4
  • 2
    What is canReadWidget doing? Can you post the code? Commented Feb 29, 2016 at 17:35
  • canReadWidget is fairly complicated - basically Widgets exist in a tree where some widgets are children of another widget type. The user can have permissions at any level in the tree. So basically canReadWidget(user, WidgetA) will check if the user has a permission for WidgetA, if so it will return True or False, otherwise it will look to the parent of WidgetA to see if there is a permission to inherit, and so on until it finds one or returns false. Commented Feb 29, 2016 at 17:49
  • 2
    You could have a look at django-guardian's object permissions. But seeing that you already implemented your own hierarchical permission logic you might not want to switch to a new process. As long as you cannot formulate your permission logic using SQL joins (either by creating your own QueryManager implementation or using custom filter queries) you cannot avoid evaluating and re-fetching as you are doing now. Commented Feb 29, 2016 at 17:53
  • If you have a tree hierarchy, you can implement a faster query with django-mptt django-mptt.github.io/django-mptt Commented Feb 29, 2016 at 19:41

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.