Paginación en DRF
PageNumberPagination
La paginación más familiar para la mayoría de APIs:
# settings.py
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}
# Paginación personalizada
from rest_framework.pagination import PageNumberPagination
class PaginacionProductos(PageNumberPagination):
page_size = 20
page_size_query_param = 'tamaño' # ?tamaño=50
max_page_size = 100
page_query_param = 'pagina' # ?pagina=2
def get_paginated_response(self, data):
return Response({
'total': self.page.paginator.count,
'paginas': self.page.paginator.num_pages,
'pagina_actual': self.page.number,
'siguiente': self.get_next_link(),
'anterior': self.get_previous_link(),
'resultados': data
})

LimitOffsetPagination
Más flexible para APIs que necesitan saltar a una posición arbitraria:
from rest_framework.pagination import LimitOffsetPagination
class PaginacionLimitOffset(LimitOffsetPagination):
default_limit = 20
max_limit = 100
limit_query_param = 'limite' # ?limite=10&desplazamiento=20
offset_query_param = 'desplazamiento'
CursorPagination
Ideal para feeds en tiempo real donde los datos cambian constantemente:
from rest_framework.pagination import CursorPagination
class PaginacionCursor(CursorPagination):
page_size = 20
ordering = '-fecha_creacion' # Debe ser un campo único y ordenado
cursor_query_param = 'cursor'
Filtrado con django-filter
pip install django-filter
# settings.py
INSTALLED_APPS += ['django_filters']
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
],
}
Filtrado básico en el ViewSet:
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import viewsets
from .models import Producto
from .serializers import ProductoSerializer
class ProductoViewSet(viewsets.ModelViewSet):
queryset = Producto.objects.all()
serializer_class = ProductoSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = ['categoria', 'activo', 'proveedor']
# Uso: /api/productos/?categoria=1&activo=true
FilterSet personalizado
Para lógica de filtrado más compleja:
import django_filters
from .models import Producto
class FiltroProducto(django_filters.FilterSet):
precio_min = django_filters.NumberFilter(field_name='precio', lookup_expr='gte')
precio_max = django_filters.NumberFilter(field_name='precio', lookup_expr='lte')
nombre = django_filters.CharFilter(lookup_expr='icontains')
creado_despues = django_filters.DateFilter(field_name='fecha_creacion', lookup_expr='gte')
creado_antes = django_filters.DateFilter(field_name='fecha_creacion', lookup_expr='lte')
categoria_nombre = django_filters.CharFilter(
field_name='categoria__nombre',
lookup_expr='icontains'
)
class Meta:
model = Producto
fields = ['activo', 'proveedor', 'precio_min', 'precio_max']
class ProductoViewSet(viewsets.ModelViewSet):
queryset = Producto.objects.select_related('categoria', 'proveedor')
serializer_class = ProductoSerializer
filterset_class = FiltroProducto
# Uso: /api/productos/?precio_min=10&precio_max=100&nombre=laptop
SearchFilter
Búsqueda de texto en múltiples campos:
from rest_framework.filters import SearchFilter, OrderingFilter
class ProductoViewSet(viewsets.ModelViewSet):
queryset = Producto.objects.all()
serializer_class = ProductoSerializer
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_class = FiltroProducto
search_fields = [
'nombre',
'descripcion',
'=categoria__slug', # Búsqueda exacta (=)
'^proveedor__nombre', # Empieza por (^)
'@descripcion', # Búsqueda full-text (@) - PostgreSQL
]
ordering_fields = ['precio', 'nombre', 'fecha_creacion', 'stock']
ordering = ['-fecha_creacion'] # Orden por defecto
# Uso búsqueda: /api/productos/?search=laptop
# Uso ordenación: /api/productos/?ordering=-precio,nombre
Combinar filtros, búsqueda y paginación
class ArticuloViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Articulo.objects.filter(publicado=True).select_related('autor', 'categoria')
serializer_class = ArticuloSerializer
pagination_class = PaginacionProductos
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['categoria', 'autor', 'destacado']
search_fields = ['titulo', 'resumen', 'contenido']
ordering_fields = ['fecha_publicacion', 'titulo', 'visitas']
ordering = ['-fecha_publicacion']
# Ejemplo de URL compleja:
# /api/articulos/?categoria=1&search=django&ordering=-visitas&pagina=2&tamaño=10
Throttling (limitación de tasa)
# settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day',
'user': '1000/day',
}
}
# Throttling por vista
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
class BusquedaViewSet(viewsets.ReadOnlyModelViewSet):
throttle_classes = [AnonRateThrottle, UserRateThrottle]
# ...
La combinación de paginación, filtrado con django-filter, búsqueda con SearchFilter y ordenación con OrderingFilter proporciona una API REST flexible y eficiente sin necesidad de escribir casi ningún código a mano.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Django es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Django
Explora más contenido relacionado con Django y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Configurar paginación con PageNumberPagination, LimitOffsetPagination y CursorPagination. Usar django-filter para filtrar por campos del modelo en la API. Aplicar SearchFilter para búsqueda de texto en múltiples campos. Implementar OrderingFilter para ordenación de resultados en la API. Crear filtros personalizados con FilterSet para lógica de filtrado compleja.
Cursos que incluyen esta lección
Esta lección forma parte de los siguientes cursos estructurados con rutas de aprendizaje