Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework permission_classes of ViewSet method

I'm writing a rest API with the Django REST framework, and I'd like to protect certain endpoints with permissions. The permission classes look like they provide an elegant way to accomplish this. My problem is that I'd like to use different permission classes for different overridden ViewSet methods.

class UserViewSet(viewsets.ModelViewSet):     queryset = User.objects.all()     serializer_class = UserSerializer      def create(self, request, *args, **kwargs):         return super(UserViewSet, self).create(request, *args, **kwargs)      @decorators.permission_classes(permissions.IsAdminUser)     def list(self, request, *args, **kwargs):         return super(UserViewSet, self).list(request, *args, **kwargs) 

In the code above I'd like to allow registration (user creation) for unauthenticated users too, but I don't want to let list users to anyone, just for staff.

In the docs I saw examples for protecting API views (not ViewSet methods) with the permission_classes decorator, and I saw setting a permission classes for the whole ViewSet. But it seems not working on overridden ViewSet methods. Is there any way to only use them for certain endpoints?

like image 764
fodma1 Avatar asked Mar 13 '16 13:03

fodma1


People also ask

What is ViewSet in Django REST framework?

A ViewSet class is simply a type of class-based View, that does not provide any method handlers such as . get() or . post() , and instead provides actions such as . list() and . create() .

What is difference between APIView and ViewSet?

APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc. Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.

What is difference between View and ViewSet in Django?

While regular views act as handlers for HTTP methods, viewsets give you actions, like create or list . The great thing about viewsets is how they make your code consistent and save you from repetition. Every time you write views that should do more than one thing, a viewset is the thing that you want to go for.


2 Answers

I think there is no inbuilt solution for that. But you can achieve this by overriding the get_permissions method:

from rest_framework.permissions import AllowAny, IsAdminUser  class UserViewSet(viewsets.ModelViewSet):     queryset = User.objects.all()     serializer_class = UserSerializer      permission_classes_by_action = {'create': [AllowAny],                                     'list': [IsAdminUser]}      def create(self, request, *args, **kwargs):         return super(UserViewSet, self).create(request, *args, **kwargs)      def list(self, request, *args, **kwargs):         return super(UserViewSet, self).list(request, *args, **kwargs)      def get_permissions(self):         try:             # return permission_classes depending on `action`              return [permission() for permission in self.permission_classes_by_action[self.action]]         except KeyError:              # action is not set return default permission_classes             return [permission() for permission in self.permission_classes] 
like image 104
ilse2005 Avatar answered Sep 19 '22 17:09

ilse2005


I created a superclass that is derived from @ilse2005's answer. In all subsequent django views you can inherit this to achieve action level permission control.

class MixedPermissionModelViewSet(viewsets.ModelViewSet):    '''    Mixed permission base model allowing for action level    permission control. Subclasses may define their permissions    by creating a 'permission_classes_by_action' variable.     Example:    permission_classes_by_action = {'list': [AllowAny],                                    'create': [IsAdminUser]}    '''     permission_classes_by_action = {}     def get_permissions(self):       try:         # return permission_classes depending on `action`         return [permission() for permission in self.permission_classes_by_action[self.action]]       except KeyError:         # action is not set return default permission_classes         return [permission() for permission in self.permission_classes] 
like image 26
Robert Christopher Avatar answered Sep 19 '22 17:09

Robert Christopher