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_namees clave: Permite desacoplar el nombre del query param del nombre del campo en la DB. Ej:min_priceen la URL mapea aprice__gteen 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 |