Querysets Dinámicos
En DRF, get_queryset() es un método disponible en vistas genéricas (como ListAPIView) que permite definir el queryset dinámicamente según el contexto de cada request. En lugar de devolver siempre los mismos datos, se puede adaptar la consulta basándose en el usuario autenticado, query params, o cualquier otra información disponible.
¿Por qué usarlo?
- Filtrado seguro: Cada usuario ve solo los datos que le corresponden; el filtro se aplica del lado del servidor.
- Performance: Filtrar en la base de datos, no en Python, evita cargar en memoria objetos innecesarios.
- Flexibilidad: El queryset se adapta a cada request: un admin ve todos los registros, un usuario regular solo los propios.
Regla de oro: Cualquier filtro de seguridad o aislamiento de datos va siempre en
get_queryset(); nunca confiar en que el cliente filtre desde el frontend.
Código de ejemplo
Una aplicación donde cada usuario tiene recursos propios (posts, órdenes, documentos, etc.). Con get_queryset() se garantiza que cada quien vea solo lo suyo:
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
class MyResourceListView(generics.ListAPIView):
"""
Cada usuario ve únicamente los recursos que le pertenecen.
"""
serializer_class = ResourceSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""
Filtra automáticamente por el usuario autenticado.
No importa qué parámetros mande el cliente, este filtro
se aplica SIEMPRE.
"""
return Resource.objects.filter(owner=self.request.user)
También se pueden combinar filtros dinámicos con condiciones:
def get_queryset(self):
user = self.request.user
qs = Resource.objects.all()
# Filtro base de seguridad
if not user.is_staff:
qs = qs.filter(owner=user)
# Filtros adicionales según query params
status = self.request.query_params.get('status')
if status:
qs = qs.filter(status=status)
return qs.order_by('-created_at')
Buenas prácticas
| Práctica | Por qué |
|---|---|
Usar select_related / prefetch_related |
Evita consultas N+1 cuando se accede a relaciones |
Mantener get_queryset() enfocado |
Si la lógica crece demasiado, moverla a un QuerySet personalizado del modelo |
| Aplicar filtros de seguridad primero | Los filtros obligatorios van en get_queryset(); los opcionales (búsqueda, orden) van con django-filter |
| No repetir lógica | Si varios views comparten el mismo filtro base, crear un mixin o una clase base |