Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django Rest framework Viewset Permissions "create" without "list"

I have the following viewset:

class ActivityViewSet(viewsets.ModelViewSet):
    queryset = Activity.objects.all()
    serializer_class = ActivitySerializer

    def get_permissions(self):
        if self.action in ['update','partial_update','destroy','list']:
            self.permission_classes = [permissions.IsAdminUser,]
        elif self.action in ['create']:
            self.permission_classes = [permissions.IsAuthenticated,]
        else :
            self.permission_classes = [permissions.AllowAny,]
        return super(self.__class__, self).get_permissions()

As seen, Im trying to allow the 'create' method without allowing the 'list', for an Authenticated user (which is not an admin). Weirdly, this Viewset results no create nor list for the Authenticated user. Iv'e checked, just to rull off, the following code:

class RouteOrderingDetail(mixins.CreateModelMixin, 
                   mixins.RetrieveModelMixin, 
                   mixins.DestroyModelMixin,
                   mixins.UpdateModelMixin,
                   viewsets.GenericViewSet):
    queryset = RouteOrdering.objects.all()
    serializer_class = RouteOrderingSerializer

This did allowed for a view in which there is create but not list (but its not usable for me, since i do need the list option avilable.

Hope the problem is clear. Any help will be appriciated.

like image 770
idik Avatar asked Nov 28 '22 04:11

idik


2 Answers

I realize this has already been answered, but wanted to share my implementation in case it better suits the OPS use case, or someone else's:

from rest_framework.authentication import TokenAuthentication, SessionAuthentication
from rest_framework.permissions import IsAuthenticated, AllowAny
from rest_framework.viewsets import ReadOnlyModelViewSet

from ..models import MyModel
from .serializers import MyModelSerializer


class ActionBasedPermission(AllowAny):
    """
    Grant or deny access to a view, based on a mapping in view.action_permissions
    """
    def has_permission(self, request, view):
        for klass, actions in getattr(view, 'action_permissions', {}).items():
            if view.action in actions:
                return klass().has_permission(request, view)
        return False


class MyModelViewSet(ReadOnlyModelViewSet):
    serializer_class = MyModelSerializer
    queryset = MyModel.objects.all()

    permission_classes = (ActionBasedPermission,)
    action_permissions = {
        IsAuthenticated: ['update', 'partial_update', 'destroy', 'list', 'create'],
        AllowAny: ['retrieve']
    }

    authentication_classes = (TokenAuthentication, SessionAuthentication)

Hopefully this help's someone out :)

like image 184
farridav Avatar answered Nov 29 '22 18:11

farridav


Maybe you can try this:

class NotCreateAndIsAdminUser(permissions.IsAdminUser):
    def has_permission(self, request, view):
        return (view.action in ['update', 'partial_update', 'destroy', 'list'] 
                and super(NotCreateAndIsAdminUser, self).has_permission(request, view))


class CreateAndIsAuthenticated(permissions.IsAuthenticated):
    def has_permission(self, request, view):
        return (view.action == 'create'
                and super(CreateAndIsAuthenticated, self).has_permission(request, view))

class NotSafeMethodAndAllowAny(permissions.AllowAny)
    def has_permission(self, request, view):
        return (view.action is not in ['update', 'partial_update', 'destroy', 'list', 'create']
                and super(NotSafeMethodAndAllowAny, self).has_permission(request, view))


class ActivityViewSet(viewsets.ModelViewSet):
    queryset = Activity.objects.all()
    serializer_class = ActivitySerializer
    permission_classes = (NotCreateAndIsAdminUser, CreateAndIsAuthenticated, NotSafeMethodAndAllowAny)

    def create(self, request):
        pass

    def list(self, request):
        pass
    ....

The reference: Allow separate permissions per View in ViewSet

Also, you might want to check out this questions which is very similar to yours: Separate permissions per methods

OR

you can do it like this:

class ActivityViewSet(viewsets.ModelViewSet):
    queryset = Activity.objects.all()
    serializer_class = ActivitySerializer

    def get_permissions(self):
        if self.action in ['update', 'partial_update', 'destroy', 'list']:
            # which is permissions.IsAdminUser 
            return request.user and request.user.is_staff
        elif self.action in ['create']:
            # which is permissions.IsAuthenticated
            return request.user and is_authenticated(request.user)             
        else :
            # which is permissions.AllowAny
            return True
like image 37
bluebird_lboro Avatar answered Nov 29 '22 18:11

bluebird_lboro