Esta es la contestación más exacta que te podemos compartir, pero primero obsérvala pausadamente y analiza si se puede adaptar a tu trabajo.
Solución:
Creo que no hay una solución incorporada para eso. Pero puede lograr esto anulando el get_permissions
método:
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]
Creé una superclase que se deriva de la respuesta de @ ilse2005. En todas las vistas posteriores de django, puede heredar esto para lograr el control de permisos de nivel de acción.
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]
Creo que todas las demás respuestas son geniales, pero no deberíamos suprimir las acciones predeterminadas. permission_classes
definido en sus decoradores directamente. Entonces,
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)]
Ahora podríamos definir el permission_classes
de estas dos maneras. Dado que definimos el valor global predeterminado permission_classes_by_action
en la superclase, podríamos descartar esa definición para todas las acciones en la opción 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
Al final de la artículo puedes encontrar las interpretaciones de otros gestores de proyectos, tú igualmente puedes dejar el tuyo si dominas el tema.