Django rest framework permission_classes of ViewSet method

前端 未结 4 2066
攒了一身酷
攒了一身酷 2020-12-08 10:43

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

4条回答
  •  心在旅途
    2020-12-08 11:08

    I think all of the other answers are great but we shouldn't suppress the default actions' permission_classes defined in their decorators directly. So,

    from rest_framework import viewsets
    from rest_framework import permissions
    
    class BaseModelViewSet(viewsets.ModelViewSet):
        queryset = ''
        serializer_class = ''
        permission_classes = (permissions.AllowAny,)
    
        # Refer to https://stackoverflow.com/a/35987077/1677041
        permission_classes_by_action = {
            'create': permission_classes,
            'list': permission_classes,
            'retrieve': permission_classes,
            'update': permission_classes,
            'destroy': permission_classes,
        }
    
        def get_permissions(self):
            try:
                return [permission() for permission in self.permission_classes_by_action[self.action]]
            except KeyError:
                if self.action:
                    action_func = getattr(self, self.action, {})
                    action_func_kwargs = getattr(action_func, 'kwargs', {})
                    permission_classes = action_func_kwargs.get('permission_classes')
                else:
                    permission_classes = None
    
                return [permission() for permission in (permission_classes or self.permission_classes)]
    

    Now we could define the permission_classes in these two ways. Since we defined the default global permission_classes_by_action in the superclass, we could drop that definition for all the actions in option 2.

    class EntityViewSet(BaseModelViewSet):
        """EntityViewSet"""
        queryset = Entity.objects.all()
        serializer_class = EntitySerializer
        permission_classes_by_action = {
            'create': (permissions.IsAdminUser,),
            'list': (permissions.IsAuthenticatedOrReadOnly,),
            'retrieve': (permissions.AllowAny,),
            'update': (permissions.AllowAny,),
            'destroy': (permissions.IsAdminUser,),
            'search': (permissions.IsAuthenticated,)  # <--- Option 1
        }
    
        @action(detail=False, methods=['post'], permission_classes=(permissions.IsAuthenticated,))  # <--- Option 2
        def search(self, request, format=None):
            pass
    

提交回复
热议问题