O Django não tem como suportar este tipo de comparação sem que o banco
de dados implemente, concorda? Se esta comparação ignorando acentos
não for feita pelo próprio mecanismo de indexação do banco de dados,
ela será muito ineficiente para qualquer coleção razoavelmente grande
de documentos.
> * Se não, qual seria a maneira ideal de eu contornar esse problema?
O que eu tenho feito é criar campos alternativos sem acentos, que eu
preencho automaticamente. Por exemplo:
class Livro(models.Model):
titulo = models.CharField(u'título', max_length=256)
titulo_busca = models.CharField(max_length=256, editable=False)
Aí eu preencho o titulo_busca automaticamente usando um método save no
model, conforme esta dica do James Bennett:
http://www.b-list.org/weblog/2006/nov/02/django-tips-auto-populated-fields/
E no método save eu uso este truque para transformar a string
acentuada em uma sem acentos:
http://www.pythonbrasil.com.br/moin.cgi/RemovedorDeAcentos
Feito isso, quando alguém faz uma busca por título, eu removo os
acentos da string a ser buscada e pesquiso no campo titulo_busca.
É assim que eu tenho feito. Não é a coisa mais simples e elegante do
mundo, mas pelo menos é 100% independente do banco de dados e tem a
melhor performance possível pois nenhuma conversão é feita nos textos
durante a busca (exceto a conversão da string a ser buscada, que é uma
só).
[ ]s
Luciano
tinha um ticket no django pedindo pelo suporte [1]
a função soundex é comum a vários banco de dados, segue abaixo:
postgresql [2]
mysql [3]
sqlite [4]
oracle [5]
[1] - http://code.djangoproject.com/ticket/8553
[2] - http://www.postgresql.org/docs/8.3/static/fuzzystrmatch.html
[3] - http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_soundex
[4] - http://www.sqlite.org/lang_corefunc.html
[5] - http://www.techonthenet.com/oracle/functions/soundex.php
Ramalho, muito boa essa sua dica! :) Vai me ser muito útil para usar
no widget autocomplete.
Para facilitar, criei um "SearchField". Acho que pode ser útil:
==SearchField ==
def to_ascii(txt, codif='utf-8'):
""""Adaptada de
http://www.pythonbrasil.com.br/moin.cgi/RemovedorDeAcentos"""
if not isinstance(txt, basestring):
txt = unicode(txt)
if isinstance(txt, unicode):
txt = txt.encode('utf-8')
return normalize('NFKD', txt.decode(codif)).encode('ASCII','ignore')
class SearchField(models.CharField):
def pre_save(self, model_instance, add):
search_text = []
for field_name in self.field_names:
val = unicode(to_ascii(getattr(model_instance, field_name)))
search_text.append(val)
value = u''.join(search_text)
setattr(model_instance, self.name, value)
return value
def __init__(self, field_names, *args, **kwargs):
self.field_names = field_names
kwargs.setdefault('max_length', 1024)
kwargs['editable'] = False
super(self.__class__, self).__init__(*args, **kwargs)
== Exemplo de uso ==
class Teste(models.Model):
texto = models.TextField()
texto_search = SearchField(field_names=['texto'])
Ele recebe como argumento "fields", aí é só escolher quais campos você
quer que ele tire os acentos e armazene.
[]'s
--
Túlio de Paiva
paiva...@gmail.com
Muito legal, Tulio, vou adotar o seu código. É uma solução parecida
com o índice SearchableText do Plone.
Só uma coisa, no método pré-save você colocou:
value = u''.join(search_text)
Tem que ser:
value = u' '.join(search_text) # note o espaço entre as aspas
Do contrário você cai concatenar palavras de campos diferentes e
armazenar palavras que não existem, o que poderia gerar resultados
esquisitos na busca.
[ ]s
Luciano
> * O Django tem suporte a comparação de strings no banco independentementeO Django não tem como suportar este tipo de comparação sem que o banco
> de acentos?
de dados implemente, concorda? Se esta comparação ignorando acentos
não for feita pelo próprio mecanismo de indexação do banco de dados,
ela será muito ineficiente para qualquer coleção razoavelmente grande
de documentos.
O que eu tenho feito é criar campos alternativos sem acentos, que eu
> * Se não, qual seria a maneira ideal de eu contornar esse problema?
preencho automaticamente. Por exemplo:
class Livro(models.Model):
titulo = models.CharField(u'título', max_length=256)
titulo_busca = models.CharField(max_length=256, editable=False)
Aí eu preencho o titulo_busca automaticamente usando um método save no
model, conforme esta dica do James Bennett:
http://www.b-list.org/weblog/2006/nov/02/django-tips-auto-populated-fields/
E no método save eu uso este truque para transformar a string
acentuada em uma sem acentos:
http://www.pythonbrasil.com.br/moin.cgi/RemovedorDeAcentos
Feito isso, quando alguém faz uma busca por título, eu removo os
acentos da string a ser buscada e pesquiso no campo titulo_busca.
É assim que eu tenho feito. Não é a coisa mais simples e elegante do
mundo, mas pelo menos é 100% independente do banco de dados e tem a
melhor performance possível pois nenhuma conversão é feita nos textos
durante a busca (exceto a conversão da string a ser buscada, que é uma
só).
Concordo que seria legal o Django incorporar se todos os bancos que
ele suporta permitem esse tipo de operação (mas não sei se isso
acontece hoje; lembrando que um dos bancos é o SQLite, que eu acho
ótimo que seja suportado oficialmente, mas é mais limitado que o
MySQL, o PostgreSQL e o Oracle).
Acho que juntando a receita do removedor de acentos com a dica do
Túlio Paiva de criar um novo field nós ficamos com uma solução muito
elegante e eficiente, e ainda fazemos algo que seria mais difícil
resolver de forma independente do banco, que é a possibilidade de
fazer a busca em vários campos de uma vez só.
Valeu, Túlio, foi legal colaborar com você!
E grato pela pergunta original, Diego, pois é como se diz: "A
necessidade é a mãe da invenção."
[ ]s
Luciano