Filtrado y Búsqueda10 temas

Filtrado y Búsqueda

Las APIs rara vez devuelven todos los datos sin filtro. Los clientes necesitan buscar, filtrar y ordenar. DRF ofrece herramientas built-in y una librería oficial (django-filter) para hacerlo de forma declarativa, segura y eficiente.

FilterSet: filtrado declarativo con django-filter

django-filter permite definir filtros reutilizables con toda la potencia del ORM de Django.

# filters.py
from django_filters import rest_framework as filters

class ProductFilter(filters.FilterSet):
    """
    Define filtros reutilizables para productos.
    - name: búsqueda parcial (case-insensitive)
    - price_min / price_max: rangos de precio
    """
    name = filters.CharFilter(lookup_expr='icontains')
    price_min = filters.NumberFilter(field_name='price', lookup_expr='gte')
    price_max = filters.NumberFilter(field_name='price', lookup_expr='lte')

    class Meta:
        model = Product
        fields = ['name', 'category', 'is_active']

Conectarlo a la vista es simple:

# views.py
from django_filters.rest_framework import DjangoFilterBackend
from .filters import ProductFilter

class ProductListView(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_class = ProductFilter

Cómo funciona

GET /api/products/?category=electronics&price_min=100&name=laptop

El DjangoFilterBackend inspecciona los query params, busca coincidencias en el FilterSet, y aplica los filtros al queryset. Los parámetros que no están definidos se ignoran silenciosamente — cero riesgo de exponer campos sensibles.

field_name es clave: Permite desacoplar el nombre del query param del nombre del campo en la DB. Ej: min_price en la URL mapea a price__gte en la DB.

SearchFilter y OrderingFilter (built-in)

Sin instalar nada extra, DRF ofrece búsqueda por texto y ordenamiento:

from rest_framework import filters

class ProductListView(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = [filters.SearchFilter, filters.OrderingFilter]
    search_fields = ['name', 'description']
    ordering_fields = ['created_at', 'price', 'name']
    ordering = ['-created_at']  # orden por defecto
GET /api/products/?search=laptop&ordering=-price

Ejemplos de uso

Request Qué hace
GET /api/products/?category=electronics Filtra por categoría exacta
GET /api/products/?price_min=100&price_max=500 Rango de precios
GET /api/products/?search=wireless Busca “wireless” en nombre y descripción
GET /api/products/?ordering=-created_at Ordena por fecha descendente
GET /api/products/?search=audio&ordering=-price&category=electronics Todo combinado

Buenas prácticas

Práctica Por qué
Seguridad primero Los filtros obligatorios (dueño del recurso) van en get_queryset(), no en el FilterSet
Un FilterSet por modelo Centralizá toda la lógica de filtrado de un recurso en una sola clase
Usar field_name No exponer los nombres reales de las columnas en la URL
SearchFilter para texto Es más simple y eficiente que django-filter para búsquedas textuales simples

Recursos

DRF Filtering Guide