0

tldr: I want to make a permission, that allows 'retrieve' action but not 'list'.

I'm writing REST API using Django Rest Framework and met a problem creating custom permission (for View from viewsets.ModelViewSet)

Got stuck creating an endpoint that should return site users:

-Admin should have permission to access every method

-Regular user should only be able to 'retrieve' and 'patch' his own account

I can't find a way to differ GET request 'list' from 'retrieve'. Checking for request.method == GET allows both of them, but I don't want user to be able to list all other users.

    from rest_framework.permissions import BasePermission

    ```

    def is_superuser(request):
         return request.user.is_superuser
        
    ```

    class IsAdminOrReadOnlyOwner(BasePermission):
        def has_permission(self, request, view):
            if is_superuser(request):
                return True
            else:
                return request.method in ['GET', 'PATCH']
        
        def has_object_permission(self, request, view, obj):
            is_owner_and_safe = int(request.user.id) == obj.id and request.method in ['GET', 'PATCH']
            return is_owner_and_safe or is_superuser(request)

Is there a way to do this, still using ModelViewSet?

Zyroox
  • 3
  • 3

2 Answers2

0

Try using self.action method in your mixin. It will give you list, retrieve, update, destroy as you action method,

Ashin Shakya
  • 690
  • 6
  • 9
  • Hmm, I wanted to have a 'plug & play' permission that I can paste in view like `permission_classes = [IsAdminOrReadOnlyOwner]`. So there is no way to do it 100% inside permission class? – Zyroox Sep 04 '21 at 14:07
0

When checking permissions, Django Rest passes the view to the permission class methods, and from the view you can determine the action. You can see an example for has_object_permission and RetrieveAPIView in the source code here.

You can use view.action to identify the action from your permission class methods, for example:

def has_permission(self, request, view):
    if is_superuser(request):
        return True
    else:
        return view.action in ['retrieve', 'update']

You can check for view.action in has_object_permission to achieve what you want.

E. Ferreira
  • 139
  • 9