Implementando un campo de busqueda en Django.

- Andrés Cruz

La mayoría de las aplicaciones que creamos o con las que interactuamos tienen muchísimos datos. Por tanto, no hace falta decir que es necesario tener una forma de buscar y filtrar los datos que necesitamos de forma rápida y eficaz. Sin más preámbulos, veamos las diversas formas en que podemos implementar la búsqueda en Django desde la búsqueda Q simple hasta la búsqueda de texto completo. Hagamos el componente de búsqueda.

<!-- search  -->
        <div class="search_form">
        <form class="search" method="GET" action="{% url 'products:search' %}">
            <label>
                <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" 
                    viewBox="0 0 32 32">
                    <path
                      d="M32 30.586l-10.845-10.845c1.771-2.092 2.845-4.791 2.845-7.741 
                      0-6.617-5.383-12-12-12s-12 5.383-12 12c0 6.617 5.383 12 
                      12 12 2.949 0 5.649-1.074 7.741-2.845l10.845 10.845 
                      1.414-1.414zM12 22c-5.514 0-10-4.486-10-10s4.486-10 
                      10-10c5.514 0 10 4.486 10 10s-4.486 10-10 10z"></path>
                  </svg>
                  <input name="q" placeholder="Search" />
            </label>
        </form>
        </div>

El componente es fácil de entender, así que vamos a diseñarlo a continuación.

.search > label {
  background-color: #fff;
  padding: 0.5rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  border-radius: 0.5rem;
  border:1px solid #000;
}

.search svg {
  fill: #000;
  width: 1.2rem;
  height: 1.2rem;
  margin-left: 0.5rem;
}

.search input {
  width: 100%;
  background: transparent;
  border: none;
  outline: none;
  color: #000;
  font-size: 13px;
}

Fácilmente y sin demasiada complejidad, digamos que tiene una tienda en línea y desea filtrar productos por su nombre o categoría, entonces puede hacer esto.

Products.objects.filter(category__contains='Laptops')

Lo que devolverá el conjunto de consultas anterior son todos los productos de la categoría Computadoras portátiles. Esa es una forma muy restrictiva de búsqueda porque tiene que coincidir exactamente con las computadoras portátiles en mayúsculas, no necesito explicar cuán limitante es eso.

Podemos mejorar esto marginalmente usando la búsqueda de campos icontains, pero todo lo que hace es hacer que el conjunto de consultas no distinga entre mayúsculas y minúsculas. Podríamos mejorar esto aún más usando funciones de base de datos, pero todavía no es suficiente, así que no entraré en ello; sin embargo, es una lectura interesante.

Digno de mención es el objeto Q que te ayudará a realizar una consulta un poco más compleja. Veamos un ejemplo y lo explicaré.

from .models import Product
from django.db.models import Q
from django.shortcuts import render

def search(request):
    q = request.GET.get('q') if request.GET.get('q') != None else ''
    products = Product.objects.get(
    Q(category__icontains=q) | 
    Q(name__icontains=q) | 
    Q(description__icontains=q)
    )
    
    context = {
        "products":products
    }
    return render(request, "search.html", context)

Lo primero que hacemos es importar el modelo sobre el que queremos ejecutar consultas en nuestro caso el modelo Producto, luego importamos el objeto Q que es el que vamos a usar para realizar consultas, y finalmente la función de renderizado. Luego tenemos una función de búsqueda que manejará todas las solicitudes de búsqueda y tenemos una variable q que simplemente obtiene lo que el usuario ingresó como términos de búsqueda en la barra de búsqueda.

Finalmente, construimos nuestra consulta. Digamos que el usuario ingresa laptop como término de búsqueda que evaluará la consulta anterior, obtenga el producto donde la categoría es como laptop o la descripción es como laptop o el nombre como laptop, que no distinguirá entre mayúsculas y minúsculas. Luego colocamos el resultado de esa consulta o la falta de ella en un diccionario de contexto y lo pasamos a la función de renderizado junto con la plantilla de búsqueda. Si bien esto es sin duda una mejora, necesita que los usuarios de la aplicación conozcan mucha información de antemano, como las categorías que podría tener, los nombres de los productos, etc., lo cual no es el caso.

Para resolver ese problema necesitamos una búsqueda de texto completo y tenemos suerte de que Django funcione bien con Postgres y Postgres tiene un motor de búsqueda de texto completo incorporado. Lea más sobre esto aquí. Django, por lo tanto, proporciona un módulo de búsqueda de Postgres aquí mismo django.contrib.postgres.search y esto es lo que vamos a utilizar para resolver algunos de los problemas anteriores para mejorar nuestra implementación de búsqueda.

Introduzcamos la búsqueda, es fácil y común buscar un solo término en una sola columna de la base de datos. Vea el ejemplo a continuación, pero para hacer esto necesitamos tener 'django.contrib.postgres' en las Aplicaciones instaladas.


from .models import Product
from django.contrib.postres import search
from django.shortcuts import render

def product_search(request):
    q = request.GET.get('q') if request.GET.get('q') != None else ''
    products = Product.objects.filter(category__search=q)
    
    context = {
        "products":products
    }
    return render(request, "search.html", context)

Entonces, mejoramos la vista que hicimos anteriormente que usaba la búsqueda Q, pero eso aún es limitante ya que solo podemos buscar en una columna, mejoremos eso introduciendo SearchVector, y de esa manera podemos ejecutar nuestra búsqueda en más de una columna. Vea el ejemplo a continuación

from .models import Product
from django.contrib.postgres import search
from django.contrib.postgres.search import SearchVector
from django.shortcuts import render
def product_search(request):
   q = request.GET.get('q') if request.GET.get('q') != None else ''
   products = Product.objects.annotate(search=SearchVector('category', 'name', 'description')).filter(search=q)
   
   context = {
       "products":products
   }
   return render(request, "search.html", context)

SearchVector nos permite ejecutar nuestras consultas en más de una columna, pero aún es limitante ya que solo podemos usar consultas de una palabra. Mejoremos esto introduciendo SearchQuery, que le permite usar más de una palabra en su término de búsqueda. Esto es fantástico porque puedes utilizar SearchQuery con varias configuraciones, lo que lo hace muy útil para buscar información en un sitio. Veamos un ejemplo y lo explico.

from .models import Product
from django.contrib.postres import search
from django.contrib.postgres.search import SearchVector, SearchQuery
from django.shortcuts import render
def product_search(request):
   q = request.GET.get('q') if request.GET.get('q') != None else ''
   products = Product.objects.annotate(
       search=SearchVector("name", "description", "category"))
       .filter(search=SearchQuery(q))
   
   context = {
       "products":products
   }
   return render(request, "search.html", context)

Hay algunas adiciones aquí, lo más importante es que hemos importado SearchQuery, que hemos agregado a nuestro conjunto de consultas y lo que eso hace es, y nos permite buscar usando más de un término. En su configuración predeterminada, search_type será simple y tratará los términos de búsqueda como palabras clave separadas, por lo que SearchQuery('hp laptop') se tratará como dos palabras clave separadas. Si configuramos search_type en una frase como SearchQuery(“hp laptop”, search_type=’phrase’), las dos palabras se tratarán como una frase. Hay otras configuraciones que puede usar con SearchQuery; consulte la documentación aquí.

Con todas las técnicas de búsqueda anteriores, devolvemos como resultado que es posible cualquier coincidencia entre el vector y la consulta. ¿Qué sucede si desea ordenar los resultados de alguna manera según su relevancia? Luego, Postgres proporciona una forma de clasificar los resultados. Consulte esta documentación para eso.

No considero esto como una guía completa para la introducción a la búsqueda, sino más bien como una forma de abrirle el apetito para comenzar a buscar en Django, por lo que le imploro que consulte las distintas partes de la documentación que tengo. adjunto en todas partes, pero espero que facilite la comprensión de algunas cosas que tal vez no resulten naturales a primera vista.

Artículo original:

https://towardsdev.com/implementing-search-in-django-568e0acc3b2d

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.