Búsquedas sin acento en Django
Igor Támara
Senior Software EngineerBuscar Bogotá o Bogota debería ofrecer el mismo resultado, los humanos no son tan estrictos, así que hay varias opciones para hacer que Django con Postgresql pueda encontrar cadenas sin importar si las personas escriben o no con acentos. En esta entrada veremos cómo configurar postgresql y Django para lograr este efecto. Personalmente creo que si hay que escribir con acentos, porque es distinto "bajo la escalera" a "bajó la escalera".
Nuestra aproximación empleará la extensión unaccent
de postgresql, aunque postgresql desde la versión 9.1 ofrece collation para contar con índices en los idiomas que se requiera, Django no tiene incorporada la opción de collation para Postgresql. Este artículo es válido hasta Django 1.6, de Django 1.7 en adelante ver al final.
Configurar postgresql
El primer paso es contar con la extensión
unaccent
, para la base de datos destino se puede emplear
psql -c "CREATE EXTENSION unaccent;" destino
La instalación de la extensión requiere que en un sistema Linux como Debian tenga el paquete contrib, por ejemplo, para postgresql 9.3:
sudo apt-get install postgresql-contrib-9.3
Mokey Patch de Django
En un archivo que se invoque la mínima cantidad de veces se puede colocar el siguiente bloque de código
from django.db.backends.postgresql_psycopg2.base import DatabaseOperations
from django.db.backends.postgresql_psycopg2.base import DatabaseWrapper
def lookup_cast(self, lookup_type):
if lookup_type in('icontains', 'istartswith', 'iexact'):
return "UPPER(unaccent(%s::text))"
elif lookup_type in('contains', 'startswith'):
return "unaccent(%s::text)"
else:
return super(DatabaseOperations, self).lookup_cast(lookup_type)
def patch_unaccent():
DatabaseOperations.lookup_cast = lookup_cast
DatabaseWrapper.operators['icontains'] = 'LIKE UPPER(unaccent(%s))'
DatabaseWrapper.operators['istartswith'] = 'LIKE UPPER(unaccent(%s))'
DatabaseWrapper.operators['iexact'] = '= UPPER(unaccent(%s))'
DatabaseWrapper.operators['contains'] = 'LIKE unaccent(%s)'
DatabaseWrapper.operators['startswith'] = 'LIKE unaccent(%s)'
patch_unaccent()
Referentes
Written by Igor Támara
A seasoned developer, Igor brings expertise in designing and building complex software systems. With a focus on quality and performance, they lead projects that drive innovation and deliver reliable solutions to meet user needs.