Melhorando as pesquisas de texto com o lookup unaccent no Django e Postgres

16/11/2020 - 2 min de leitura

DJANGO

As pesquisas em campo de texto no Django são cheias de opções. Por exemplo, você pode filtrar por uma texto que contém outra string, que é o caso do .filter(name__contains=[busca]). Esse lookup contains gera um SQL mais ou menos assim:

SELECT ... FROM minha_tabela WHERE name LIKE '%busca%';

Essa query vai retornar algum nome que tiver o Gab no meio. Para amplificar mais ainda o campo da pesquisa, podemos avisar o Django para ignorar as letras de maiúsculas e minúsculas. Para isso, utilizamos o __icontains no lugar. O que vai acontecer é que, no caso da pesquisa por 'Gab', o Django vai retorar qualquer nome que tiver GAB, gAB, GaB, gab, gaB, etc... Bem mais amplo. Geralmente usamos isso em funcionalidades de pesquisa.

Porém, o post de hoje trata-se do lookup __unaccent. O UNACCENT é uma extesnão do PostgreSQL que a gente pode extender no Django.

O problema

O __icontains resolve boa parte dos problemas, porém caso os dados tenham algum acento, que é bastante comum na língua portuguesa, o usuário deveria informar os acentos, para que o Django encontrasse os nomes.

Exemplo Prático:

Person.objects.filter(name__icontains='arao')

Buscando usuários com o nome Arão, meu usuário não digitou o acento -> ~ (til) na hora da pesquisa e, mesmo existindo registros que contém o nome arão, o Django retornou uma query vazia. Isso acontece porque o Django e o Python considera 'a' != 'ã'.

Solução

A gente, como desenvolvedor, não pode ficar dependendo do cenário perfeito, que é quando o usuário digita o nome correto, com todos as pontuações.

Felizmente, o PostgreSQL tem uma extensão chamada UNACCENT, que ignora completamente os acentos das palavras. Ou seja, com o UNACCENT, 'a' = 'ã'.

Para habilitar esse recurso, primeiramente você deve usar o PostgreSQL como BD. Após isso, deve adicionar a app 'django.contrib.postgres' na sua lista de aplicações instaladas. Algo assim:

INSTALLED_APPS = [
    # apps do django
    'django.contrib.postgres',
    # apps de terceiros
    # minhas apps
]

Após isso, você deve informar ao PostgreSQL que você quer essa extensão funcionando, pois ela não vem ativada por padrão no BD.

Entre via terminal no seu BD PostgreSQL:

psql meu_bd
ou algo como:
psql -h localhost -U usuario_do_bd -d meu_bd -W

O comando de entrada vai mudando conforme o SO e o usuário que você esteja utilizando.

Uma vez que você conseguiu entrar via psql, deverá ter algo parecido com isso:

psql (versao)
Type "help" for help.

meu_bd=#

Daí é só digitar o comando:

CREATE EXTENSION UNACCENT;

Agora no Django é só usar o lookup __unaccent nas buscas ❤️

Você também pode combinar os lookups no django, por esexmplo, o __unaccent com o __icontains. Ficaria mais ou menos assim:

Person.objects.filter(name__unaccent__icontains='arao')

Bônus

Existe também um lookup no PostgreSQL que retorna pesquisas similares. Por exemplo, seu usuário digitou "quato" ao invés de "quarto", com o lookup __trigam_similar podemos contornar esse pequeno erro. Você pode olhar melhor na documentação do Django.

Foto da capa by Markus Winkler on Unsplash

Compartilhe

Twitter