Object permission function firing more than once

Viewed 315

I'm using Django Rest Framework. I want to give permission class to RetrieveUpdateDestroyAPI View

My permission class:

class AssetItemPermission(permissions.BasePermission):
    def has_object_permission(self, request, view, obj):
        user = request.user
        shared_item_course = False

        is_content_author = PermissionHelper().check_permission(
            request.user, ['create_content'])

        courses = Course.objects.filter(module=obj)

        if any(obj.tenant in course.tenants.all() for course in courses):
            shared_item_course = True
        elif any(obj.status==TenantShareItemStatusValues.SHARED_TO_ALL.value for course in courses):
            shared_item_course = True

        if Enrolment.objects.filter(enrollable__in=courses, enrollee=request.user, 
                                    status=EnrolmentStatus(short_name=EnrolmentStatusValues.APPROVED.value)
                                   ).exists():
            print("Is enrolled by user")
            return True
        elif is_content_author and obj.tenant == request.user.tenant:
            print("is content author and it is in tenant")
            return True
        elif is_content_author and shared_item_course:
            print("is content author and it is in tenant share item")
            return True

        return False

My View:

class AssetItemView(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = AssetItemsSerializer
    permission_classes = [AssetItemPermission]

    def get_queryset(self):
        return Module.objects.filter(id=self.kwargs['pk'])

It works but I see the permission check is firing 5 times in my case:

For example, the print statement "is content author and it is in tenant" is printing 5 times instead of one. Why is this firing 5 times?

1 Answers

The first permission check is to see that the user is able to access the requested resource. After that each of those permission checks is being run by the BrowsableAPIRenderer to see if the user has access to the HTTP methods PUT, PATCH DELETE, and OPTIONS, in order to determine if the rendered template should include buttons that will allow you to take those actions on the requested resource. That first permission check is whether you have a GET permission. When I run this locally, I'm actually seeing 6 checks, because PUT is getting checked twice, though I'm not sure why.

You can see this in action if you add a print(request.method) line in has_object_permission.

If you add ?format=json to the end of your URL, or just add format=json to the query string if you have additional parameters there, you will force the use of the JSONRenderer, which will only fetch and return the data, without the browsable API template. Thus, those extra permission checks aren't necessary to see if the renderer should create those buttons on the template. JSONRenderer will only run the single permissions check on the GET request.

Related