django rest framework filter_backends class called before permission_classes class

927 views Asked by At

I have a DRF view-set with a custom permission and filter. In DRF's official docs it says:

Permission checks are always run at the very start of the view, before any other code is allowed to proceed.

But I have noticed that my filter_backend class is called before permission_class. Here is my code:

# my permission
from rest_framework import permissions


class CompanyAccessPermission(permissions.BasePermission):
    message = 'Detail of company not allowed.'

    def has_object_permission(self, request, view, obj):
        print("permission")
        return request.user in obj.users.all()
# my filter
from rest_framework import filters


class IsCompanyOwnerFilterBackend(filters.BaseFilterBackend):

    def filter_queryset(self, request, queryset, view):
        print("filter")
        return queryset.filter(users__in=[request.user])
# my view
from rest_framework import mixins, viewsets
from rest_framework.permissions import IsAuthenticated

from api import filters, permissions, serializers
from core import models


class CompanyViewSet(viewsets.GenericViewSet,
                     mixins.ListModelMixin,
                     mixins.RetrieveModelMixin):

    permission_classes = (IsAuthenticated, permissions.CompanyAccessPermission)
    filter_backends = [filters.IsCompanyOwnerFilterBackend]
    queryset = models.Company.objects.all()
    serializer_class = serializers.CompanySerializer

So when I want to retrieve a Company object the output is as follows:

> filter
> permission

I was expecting the opposite of that. I also looked at the source code of DRF class GenericViewSet(ViewSetMixin, generics.GenericAPIView). It seems like the permission class (called in views.APIView) is called before the filter backend class (called in generics.GenericAPIViewi which inherits views.APIView). What am I missing?

1

There are 1 answers

0
cagrias On BEST ANSWER

Okay I have noticed what's going on. Here is the execution of permission_class methods and filter_backend_methods:

  1. permission_classes' .has_permission(self, request, view) method, which I did not override.
  2. filter_backends' .filter_queryset(self, request, queryset, view) method.
  3. permission_classes' .has_object_permission(self, request, view, obj) method, which I did override.

As I was performing an object-level permission (overridinghas_object_permission method), my custom filter was executed before, which makes more sense.