2011-04-11 60 views
8

Hola, me parece que en la base de datos de postgres, no podemos configurar la sensibilidad de acento por defecto (en intercambios de correo antiguos).cómo tener filtro insensible al acento en django con postgres?

¿Hay alguna manera de tener un _icontains también insensible a caracteres especiales (é, è, à, ç, ï) o debo usar postgres regex para reemplazar ambos lados con _iregex (ç-> c, é-> e ...)?

editar: esta pregunta es anterior y se guarda para los usuarios de django anteriores a la 1.8. Para aquellos que usan las últimas versiones de django, aquí la nueva forma: https://docs.djangoproject.com/en/dev/ref/contrib/postgres/lookups/#std:fieldlookup-unaccent

Respuesta

7

EDIT: Django 1.8 hace que el acento de búsqueda unsensitive de orden interna PostgreSQL. https://docs.djangoproject.com/en/dev/ref/contrib/postgres/lookups/#std:fieldlookup-unaccent

De hecho en Postgres contrib (8.4+) hay una función para buscar fácilmente unaccent:

para postgres 9/8.5:

para postgres 8.4:

aquí un ejemplo de uso de Django:

vals = MyObject.objects.raw(
     "SELECT * \ 
     FROM myapp_myobject \ 
     WHERE unaccent(name) LIKE \'%"+search_text+"%'") 

Puede Aplicar unaccent de búsqueda de texto antes de la comparación.

opción que hice es:

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
# parts of credits comes to clarisys.fr 
from django.db.backends.postgresql_psycopg2.base import * 

class DatabaseOperations(DatabaseOperations): 
    def lookup_cast(self, lookup_type): 
     if lookup_type in('icontains', 'istartswith'): 
      return "UPPER(unaccent(%s::text))" 
     else: 
      return super(DatabaseOperations, self).lookup_cast(lookup_type) 

class DatabaseWrapper(DatabaseWrapper): 
    def __init__(self, *args, **kwargs): 
     super(DatabaseWrapper, self).__init__(*args, **kwargs) 
     self.operators['icontains'] = 'LIKE UPPER(unaccent(%s))' 
     self.operators['istartswith'] = 'LIKE UPPER(unaccent(%s))' 
     self.ops = DatabaseOperations(self) 

usan este archivo base.py en una carpeta y utilizar esta carpeta como backend db. icontains e istartswith son ahora insensibles a mayúsculas y minúsculas.

+0

¿Cómo usar la carpeta como back-end de db? ¿Debo ponerlo en el directorio usr/local/lib/python2.7/dist-packages/django/db/backends o debo declararlo de alguna manera? – Falcoa

+1

si no se utiliza Django 1.8, sólo tiene que utilizar la ruta salpicada de pitón en su base de datos BASES DE DATOS = { "por defecto": { "MOTOR": "my_app.my_backend_module" [...]}} i – christophe31

+0

Agregué la ruta de puntos de python en el backend de la base de datos, pero obtuve un error ImproperlyConfigured: raise ImproperlyConfigured (error_msg) django.core.exceptions.ImproperlyConfigured: 'myAPP.backends.base' no es un back-end de base de datos disponible. Trate de usar 'django.db.backends.XXX', donde XXX es uno de: u'mysql 'u'oracle', u'postgresql_psycopg2' , u'sqlite3' error fue: Sin módulo denominado base de ¿Le ¿Sabes qué debo hacer para resolver este error? – Falcoa

1

No creo que puedan usar las búsquedas de campo estándar de Django para esto a menos que almacenen una versión no acentuada de su texto en otro columna y hacer la búsqueda allí. Puede agregar una columna duplicada con editable = False y anular el método save() del modelo para actualizar ese campo desde el texto acentuado original.

Python: Remove accents from unicode

PostgreSQL Wiki: Strip accents from strings, and output in lowercase

+0

triste respuesta, espero encontrar una mejor manera de hacer que añadir una columna para cada campo de búsqueda de texto en mi db. No veo exactamente cómo estoy casi seguro de que Regex puede hacer el trabajo. – christophe31

7

Me las arreglé para instalar abando de postgresql contrib, pero this answer that patches django no funcionó. load_backend en django.db.utils impone que el nombre de backend comience con django.db.backends.

La solución que funcionó para mí estaba insertando el código en uno de mis módulos:

from django.db.backends.postgresql_psycopg2.base import DatabaseOperations, DatabaseWrapper 

def lookup_cast(self, lookup_type): 
    if lookup_type in('icontains', 'istartswith'): 
     return "UPPER(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))' 
    print 'Unaccent patch' 

patch_unaccent() 

búsquedas Ahora unaccent están trabajando muy bien, incluso en el interior de administración de Django! ¡Gracias por su respuesta anterior!

+1

raro, mi solución tiene cierta especificidad. El archivo debe llamarse base.py, settings.py debe usar su carpeta principal como back-end, y no debe reemplazar el comodín por clase usada en este archivo. (es una especie de herencia de módulo). – christophe31

+0

Pero su solución es excelente. El mío solo permite establecer el comportamiento en el nivel de settings.py. (El tuyo también puede hacerlo si pones este parche en una aplicación aislada models.py.) – christophe31

+1

Eso es realmente extraño, porque nombré el archivo base.py y lo utilicé como el servidor, pero recibí un error configurado incorrectamente. De todos modos, gracias por apuntarme en la dirección correcta. Las búsquedas sin aroma son algo que mis clientes realmente necesitan. – bbrik

0

Estoy trabajando en un campo de búsqueda no acentuado para django y postgreSQL.Está en github: https://github.com/marianobianchi/django-accent-free-lookup

Está funcionando bien por ahora, pero todavía necesita mucho trabajo. Lo estoy usando y no muestra ningún problema por el momento.

La forma de usarlo es crear un nuevo administrador para el modelo que desea que tenga búsquedas no acentuadas (consulte el ejemplo almacenado al final del archivo managers.py en el proyecto).

Las búsquedas ya he implementar son:

Son equivalentes a las operaciones de búsqueda de campo comunes que vienen con Django:

"__exact"

"__iexact"

"__contains"

"__icontains"

con la diferencia de que son "acento insensible" para los personajes acentuados más comunes.

+0

Encuentro mi camino más interesante porque si alguien usa la búsqueda de administrador será desacostumbrado, incluso más, si quiere cambiar a mysql, perderá insensibilidad de acento pero todo lo demás funcionará ... – christophe31

+0

Tienes razón, esta es solo otra posibilidad, probablemente no la mejor para todos. Aún no lo probé con mysql, pero si mysql admite la búsqueda de django regex, esta aplicación debería funcionar tan bien como con postgreSQL. – marianobianchi

+0

regexlookup usa el lenguaje sql regex o el lenguaje python regex para sqlite entonces, si la sintaxis regex que usas es synonim para postgres y mysql debería funcionar pero probablemente no funcione con sqlite. – christophe31

1

Acabo de lanzar (hace unos días) la biblioteca django-alabasca que agrega operadores al django ORM para búsqueda acentuada. Monopatch el django ORM y utiliza la función unaccent() de postgres para hacerlo.

Por favor, mira esto =>https://github.com/djcoin/django-unaccent

Cuestiones relacionadas