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?
Okay I have noticed what's going on. Here is the execution of permission_class methods and filter_backend_methods:
.has_permission(self, request, view)method, which I did not override..filter_queryset(self, request, queryset, view)method..has_object_permission(self, request, view, obj)method, which I did override.As I was performing an object-level permission (overriding
has_object_permissionmethod), my custom filter was executed before, which makes more sense.