Eu estou com aquele velho problema: Preciso fazer uma busca no banco por 'jose' e tenho que obter como resposta os registros que tiverem o valor 'jose' e 'josé' (com acento).
Eu dei uma boa procurada hoje e não achei nenhuma solução atrelada ao ORM do Django. Tudo que eu encontrei foram algumas funções internas do banco de dados que convertem o conteúdo do campo pra ascii removendo assim os acentos (testei no postgres e tem um comportamento muito estranho por sinal ...). Bom, não tenho uma estratégia em mente pra resolver esse problema. To cansado, tomara que eu esteja viajando e a solução esteja debaixo do meu nariz :D
Minhas indagações são:
* O Django tem suporte a comparação de strings no banco independentemente de acentos? * Se não, qual seria a maneira ideal de eu contornar esse problema?
> Eu estou com aquele velho problema: Preciso fazer uma busca no banco por
> 'jose' e tenho que obter como resposta os registros que tiverem o valor
> 'jose' e 'josé' (com acento).
> Eu dei uma boa procurada hoje e não achei nenhuma solução atrelada ao ORM do
> Django. Tudo que eu encontrei foram algumas funções internas do banco de
> dados que convertem o conteúdo do campo pra ascii removendo assim os acentos
> (testei no postgres e tem um comportamento muito estranho por sinal ...).
> Bom, não tenho uma estratégia em mente pra resolver esse problema. To
> cansado, tomara que eu esteja viajando e a solução esteja debaixo do meu
> nariz :D
> Minhas indagações são:
> * O Django tem suporte a comparação de strings no banco independentemente
> de acentos?
> * Se não, qual seria a maneira ideal de eu contornar esse problema?
> Eu estou com aquele velho problema: Preciso fazer uma busca no banco por > 'jose' e tenho que obter como resposta os registros que tiverem o valor > 'jose' e 'josé' (com acento).
> Eu dei uma boa procurada hoje e não achei nenhuma solução atrelada ao ORM do > Django. Tudo que eu encontrei foram algumas funções internas do banco de > dados que convertem o conteúdo do campo pra ascii removendo assim os acentos > (testei no postgres e tem um comportamento muito estranho por sinal ...). > Bom, não tenho uma estratégia em mente pra resolver esse problema. To > cansado, tomara que eu esteja viajando e a solução esteja debaixo do meu > nariz :D
> Minhas indagações são:
> * O Django tem suporte a comparação de strings no banco independentemente > de acentos?
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:
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ó).
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]
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
> Ele recebe como argumento "fields", aí é só escolher quais campos você > quer que ele tire os acentos e armazene.
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.
>> Ele recebe como argumento "fields", aí é só escolher quais campos você
>> quer que ele tire os acentos e armazene.
> Muito legal, Tulio, vou adotar o seu código. É uma solução parecida
> com o índice SearchableText do Plone.
Que bom que o código foi útil! :)
> 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.
É verdade! Como acabei de escrever o código e não testei com vários
campos, não tinha me atentado para isso. :P
> > 2008/11/30 Túlio Paiva <paivatu...@gmail.com>:
> >> 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
> >> Ele recebe como argumento "fields", aí é só escolher quais campos você
> >> quer que ele tire os acentos e armazene.
> > Muito legal, Tulio, vou adotar o seu código. É uma solução parecida
> > com o índice SearchableText do Plone.
> Que bom que o código foi útil! :)
> > 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.
> É verdade! Como acabei de escrever o código e não testei com vários
> campos, não tinha me atentado para isso. :P
> > * O Django tem suporte a comparação de strings no banco > independentemente > > de acentos?
> 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.
> 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ó).
Excelente dica Luciano ... Acho que vou adotar essa solução!! Brigadão.
Mas ... como o Danilo falou se todos os bancos que os Django suporta tem metodos para realizar essa operação acho que faria sentido o Django disponibilizar um suporte para essas operações sim.
> Excelente dica Luciano ... Acho que vou adotar essa solução!! Brigadão.
> Mas ... como o Danilo falou se todos os bancos que os Django suporta tem > metodos para realizar essa operação acho que faria sentido o Django > disponibilizar um suporte para essas operações sim.
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."
Acabei de inaugurar o meu blog e postar o SearchField:
http://paivatulio.wordpress.com/.
Além do que foi discutido aqui, também mostrei lá como integrar com o
site de administração do Django.
> 2008/12/1 Diego Martins <conc...@gmail.com>:
>> Excelente dica Luciano ... Acho que vou adotar essa solução!! Brigadão.
>> Mas ... como o Danilo falou se todos os bancos que os Django suporta tem
>> metodos para realizar essa operação acho que faria sentido o Django
>> disponibilizar um suporte para essas operações sim.
> 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."
Eu tenho uma idéia que talvez possa ajudar. Seria algo do tipo:
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(*field_name+':"'+*val*+'"'*)
value = u''.join(search_text)
setattr(model_instance, self.name, value)
return value
Isso faria com que o armazenado no banco fosse algo do tipo:
nome_do_campo:"valor_do_campo"
Isso seria bom se o campo de busca tivesse o valor de mais de um campo, aí o
usuário poderia definir em qual campo utilizar usando essa sintaxe ou então
sem precisar especificar o nome do campo...
> Acabei de inaugurar o meu blog e postar o SearchField:
> http://paivatulio.wordpress.com/.
> Além do que foi discutido aqui, também mostrei lá como integrar com o
> site de administração do Django.
> > 2008/12/1 Diego Martins <conc...@gmail.com>:
> >> Excelente dica Luciano ... Acho que vou adotar essa solução!! Brigadão.
> >> Mas ... como o Danilo falou se todos os bancos que os Django suporta tem
> >> metodos para realizar essa operação acho que faria sentido o Django
> >> disponibilizar um suporte para essas operações sim.
> > 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."
Vinicius acho que vc foi muito infeliz na sua colocação, poderia ter criado vários flamers, estude um pouco mais antes de criticar o trabalho de outros grupos esta é uma boa dica até de vida.
>> > 2008/11/30 Túlio Paiva <paivatu...@gmail.com>: >> >> 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
>> >> Ele recebe como argumento "fields", aí é só escolher quais campos você >> >> quer que ele tire os acentos e armazene.
>> > Muito legal, Tulio, vou adotar o seu código. É uma solução parecida >> > com o índice SearchableText do Plone.
>> Que bom que o código foi útil! :)
>> > 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.
>> É verdade! Como acabei de escrever o código e não testei com vários >> campos, não tinha me atentado para isso. :P
> Vinicius acho que vc foi muito infeliz na sua colocação, poderia ter criado
> vários flamers, estude um pouco mais antes de criticar o trabalho de outros
> grupos esta é uma boa dica até de vida.
>>> > 2008/11/30 Túlio Paiva <paivatu...@gmail.com>:
>>> >> 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
>>> >> Ele recebe como argumento "fields", aí é só escolher quais campos você
>>> >> quer que ele tire os acentos e armazene.
>>> > Muito legal, Tulio, vou adotar o seu código. É uma solução parecida
>>> > com o índice SearchableText do Plone.
>>> Que bom que o código foi útil! :)
>>> > 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.
>>> É verdade! Como acabei de escrever o código e não testei com vários
>>> campos, não tinha me atentado para isso. :P
>>> > [ ]s
>>> > Luciano
>>> []'s
>>> --
>>> Túlio de Paiva
>>> paivatu...@gmail.com
> --
> Rodrigo Pinheiro Matias
> Bacharel em Ciência da Computação
> Celular
> +55 (063) 9237.3480
> Telefone em horário Comercial
> +55 (063) 3221.2344