[Fixed]-Permission checks in DRF viewsets are not working right

26๐Ÿ‘

โœ…

OK, so after reading a bunch of DRFโ€™s code and posting an issue at the DRF GitHub page.

It seems that has_object_permission() only gets called if your view calls get_object() to retrieve the object to be operated on.

It makes some sense since you would need to retrieve the object to check permissions anyway and if they did it transparently it would add an extra database query.

The person who responded to my report said they need to update the docs to reflect this. So, the idea is that if you want to write a custom detail route and have it check permissions properly you need to do

class MyViewSet(ModelViewSet):
    queryset = MyModel.objects.all()
    ....
    permission_classes = (MyCustomPermissions, )
    
        @detail_route(methods=['GET', ])
        def custom(self, request, pk=None):
            my_obj = self.get_object() # do this and your permissions shall be checked
            return Response('whatever')
๐Ÿ‘คMad Wombat

0๐Ÿ‘

In my case I didnโ€™t address requests correctly so my URL was api/account/users and my mistake was that I set URL in frontend to api/account/ and thats not correct!

๐Ÿ‘คBambier

-1๐Ÿ‘

If you want to define permissions while doing another method that doesnโ€™t call the get_object() (e.g. a POST method), you can do overriding the has_permission method. Maybe this answer can help (https://stackoverflow.com/a/52783914/12737833)

Another thing you can do is use the check_object_permissions inside your POST method, that way you can call your has_object_permission method:

@action(detail=True, methods=["POST"])
def cool_post(self, request, pk=None, *args, **kwargs):
    your_obj = self.get_object()
    self.check_object_permissions(request, your_obj)

Leave a comment