Permisos Avanzados
DRF ofrece un sistema de permisos flexible y componible. Desde roles simples hasta lógica condicional compleja, se puede controlar exactamente quién hace qué en la API.
Custom Permission básica
from rest_framework.permissions import BasePermission
class IsStaff(BasePermission):
"""Solo usuarios staff pueden acceder."""
def has_permission(self, request, view):
return request.user and request.user.is_staff
Permission a nivel de objeto
Controla el acceso según el dueño del recurso:
class IsOwner(BasePermission):
"""
- GET, HEAD, OPTIONS: cualquiera autenticado puede leer
- PUT, PATCH, DELETE: solo el owner puede modificar
"""
def has_object_permission(self, request, view, obj):
if request.method in ('GET', 'HEAD', 'OPTIONS'):
return True
return obj.author == request.user
Nota:
has_object_permissionse ejecuta DESPUÉS dehas_permission. Si esta última falla, nunca llega al nivel de objeto. Además, solo se invoca si la vista obtiene el objeto explícitamente (vistas genéricas lo hacen automáticamente).
Permisos dinámicos por acción
Diferentes acciones del ViewSet pueden tener diferentes permisos:
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework.decorators import action
class PostViewSet(ModelViewSet):
def get_permissions(self):
if self.action == 'create':
return [IsAuthenticated()]
elif self.action in ('destroy', 'close'):
return [IsAdminUser()]
return [IsAuthenticated()]
@action(detail=True, methods=['post'])
def close(self, request, pk=None):
"""Cerrar un post — solo admins."""
post = self.get_object()
post.status = 'closed'
post.save()
return Response({'status': 'closed'})
Composición de permisos
Combinar permisos con AND / OR:
from rest_framework.permissions import OR
# OR: cualquiera que pase
class PostViewSet(ModelViewSet):
permission_classes = [OR(IsAdminUser, IsOwner)]
# AND: todos deben pasar (es el default, solo listarlos)
class PostViewSet(ModelViewSet):
permission_classes = [IsAuthenticated, IsStaff]
Resumen de patrones
| Patrón | Implementación | Caso de uso |
|---|---|---|
| Rol simple | BasePermission.has_permission() |
“Solo admins” |
| Object-level | BasePermission.has_object_permission() |
“Solo el dueño puede editar” |
| Dinámico por acción | ViewSet.get_permissions() |
Diferentes permisos por endpoint |
| Composición | AND(), OR() |
Condiciones complejas |
| Grupos | user.groups.filter(...) |
Integración con sistema de grupos de Django |
Diferencia clave:
has_permissioncontrola el acceso al endpoint (nivel vista).has_object_permissioncontrola el acceso al recurso específico (nivel objeto). Usar ambas cuando se necesiten las dos capas.