En este artículo te voy a mostrar cómo integrar un buscador funcional y potente en la plantilla base de un proyecto Django orientado a una tienda de videojuegos. Vamos a construirlo paso a paso, incluyendo búsqueda por nombre, descripción, géneros y plataformas, y mejorando la búsqueda para que sea flexible con las palabras introducidas.
Estructura base del proyecto
Tenemos un proyecto con una app llamada juegos
que contiene el modelo Juego
con relaciones a modelos Genero
y Plataforma
. Usamos Bootstrap para el diseño y queremos añadir el buscador en el header, para que esté disponible globalmente.
La plantilla base (main.html) tiene un header con logo, título y el espacio para el formulario de búsqueda.
Formulario de búsqueda en el header
Queremos que el formulario ocupe solo 4 columnas (en un sistema de 12 columnas de Bootstrap) y tenga un estilo compacto.
<form method="GET" action="{% url 'juegos.index' %}" class="search-form d-flex align-items-center" role="search" aria-label="Buscar videojuegos"> <input class="form-control form-control-sm search-input" type="search" name="q" placeholder="Buscar..." aria-label="Buscar videojuegos" value="{{ request.GET.q|default:'' }}"> <button class="btn btn-outline-primary btn-sm search-button" type="submit" title="Buscar"> <i class="fas fa-search"></i> </button> </form>
Este formulario va dentro de una columna <div class="col-md-4">
para controlar el ancho.
Estilos CSS externos para el buscador
Para mantener el código limpio y escalable, los estilos del formulario se colocan en un archivo CSS aparte (static/css/styles.css en el caso concreto de este proyecto):
.search-form { width: 100%; max-width: 300px; } .search-input { font-size: 0.875rem; padding: 0.25rem 0.5rem; } .search-button { font-size: 0.875rem; padding: 0.25rem 0.5rem; }
Esto hace que el buscador sea pequeño, elegante y responsivo.
Configuración de URLs
Definimos en juegos/urls.py
las rutas:
from django.urls import path from . import views urlpatterns = [ path('', views.index, name='juegos.index'), path('<int:id>/', views.mostrar, name='juegos.mostrar'), ]
Vista index
con lógica de búsqueda avanzada
El corazón del buscador es la vista que lista juegos y aplica filtros basados en la consulta del usuario. Edita el archivo juegos/views.py
Queremos que la búsqueda:
- Funcione con varias palabras separadas por espacios.
- Busque en los campos: nombre, descripción, géneros y plataformas.
- Permita buscar por palabras parciales, así "ps" encuentre "ps5".
- Permita buscar con palabras múltiples, por ejemplo "juegos ps5" debe encontrar juegos que contengan "juegos" y "ps5" en cualquier campo.
from django.shortcuts import render from django.db.models import Q from .models import Juego def index(request): query = request.GET.get('q', '').strip() juegos = Juego.objects.all().prefetch_related('generos', 'plataformas') if query: palabras = query.split() filtro = Q() for palabra in palabras: filtro &= ( Q(nombre__icontains=palabra) | Q(descripcion__icontains=palabra) | Q(generos__nombre__icontains=palabra) | Q(plataformas__nombre__icontains=palabra) ) juegos = juegos.filter(filtro).distinct() datos_plantilla = { 'titulo': 'Catálogo de videojuegos', 'juegos': juegos } plantilla_principal = { 'title': 'Catálogo de videojuegos' } return render(request, 'juegos/index.html', { 'datos_plantilla': datos_plantilla, 'plantilla_principal': plantilla_principal })
Explicación del filtro
query.split()
separa la búsqueda en palabras.- Por cada palabra, creamos una condición que busca esa palabra en cualquiera de los campos relevantes (
nombre
,descripcion
,generos.nombre
,plataformas.nombre
). - Usamos
filtro &= (...)
para que todas las palabras deban estar presentes en alguna de las columnas (AND entre palabras, OR dentro de cada palabra en los campos). distinct()
evita duplicados por los joins en las relaciones.