2010-06-04 18 views
6

Tengo problemas para almacenar y generar un personaje ndash como UTF-8 en Django.¿La doble codificación de Django es una cadena Unicode (utf-8?)?

Obtengo datos de una API. En forma cruda, como recuperada y vista en un editor de texto, dada unidad de datos puede ser similar a:

"I love this detergent \u2013 it is so inspiring." 

(\ u2013 es & ndash; como una entidad html).

Si obtengo esto directamente de una API y lo visualizo en Django, no hay problema. Se muestra en mi navegador como una larga carrera. Me di cuenta de que tengo que hacer decode('utf-8') para evitar el error "'codec ascii no puede codificar el carácter" si trato de hacer algunas operaciones con ese texto en mi opinión, sin embargo. El texto va a la plantilla como "Me encanta este detergente \ u2013, es muy inspirador", según la barra de herramientas Django Debug.

Cuando se almacena a MySQL y leer para la salida a través del mismo punto de vista y la plantilla, sin embargo, termina pareciéndose a

"I love this detergent – it is so inspiring" 

Mi tabla de MySQL se establece en DEFAULT CHARSET=utf8.

Ahora, cuando leo los datos de la base de datos a través de monitor de MySQL en un terminal ajustado en UTF-8, se muestra como

"I love this detergent – it is so inspiring" 

(correcto - muestra un ndash)

Cuando utilizo MySQLdb en una cáscara de pitón, esta línea es

"I love this detergent \xe2\x80\x93 it is so inspiring" 

(este es el UTF-8 correcta para un ndash)

Sin embargo, si me quedo python manage.py shell, y luego

In [1]: import myproject.myapp.models ThatTable 
In [2]: msg=ThatTable.objects.all().filter(thefield__contains='detergent') 
In [3]: msg 
Out[4]: [{'thefield': 'I love this detergent \xc3\xa2\xe2\x82\xac\xe2\x80\x9c it is so inspiring'}] 

Me parece que Django ha tomado \xe2\x80\x93 a significar tres personajes distintos, y codificado como UTF-8 en \xc3\xa2\xe2\x82\xac\xe2\x80\x9c. Esto se muestra como â € "porque \ xe2 parece ser â, \ x80 parece ser €, etc. Lo he comprobado y este es cómo se lo está enviando a la plantilla, también.

Si decodifica la secuencia larga en Python, sin embargo, con decode('utf-8'), el resultado es \xe2\u20ac\u201c que también se representa en el navegador como â € ". Intentar decodificar nuevamente produce un UnicodeDecodeError.

He seguido el Django suggestions for Unicode, hasta donde yo sé (configurado MySQL).

¿Alguna sugerencia sobre lo que puedo haber configurado mal?

adición parece que este mismo problema ha surgido en otras áreas o sistemas, así., Como durante la búsqueda de \ xc3 \ xa2 \ XE2 \ x82 \ XAC \ XE2 \ x80 \ x9c, he encontrado en http://pastie.org/908443.txt una secuencia de comandos para "reparar entidades UTF8 incorrectas.", que también se encuentra en un complemento de importación de WordPress. Simplemente reemplaza esta secuencia con –. Sin embargo, me gustaría resolver esto de la manera correcta.

Ah, y estoy usando Django 1.2 y Python 2.6.5.

Puedo conectarme a la misma base de datos con PHP/PDO e imprimir estos datos sin hacer nada especial, y se ve bien.

Respuesta

1

Esto parece un caso de doble codificación; No tengo mucha experiencia con Python, pero intente ajustar la configuración de la conexión de MySQL, según el consejo en http://tahpot.blogspot.com/2005/06/mysql-and-python-and-unicode.html

Lo que supongo que está sucediendo es que la conexión es latin1, por lo MySQL intenta codificar la cadena de nuevo antes almacenamiento en el campo UTF-8. El código de allí, específicamente este bit:

EDIT: Con Python al establecer una conexión de base de datos añadir el siguiente bandera: init_command = 'UTF-8 nombres de los conjuntos'.

Además establecer lo siguiente en my.cnf de MySQL: default-character-set = UTF-8

es probablemente lo que quiere.

+0

Es extraño, pero llamar a 'set names utf8' empeora el problema. Al dejar a Django fuera de la imagen, en un shell de Python, hace que ese carácter sea '\ xc3 \ xa2 \ xe2 \ x82 \ xac \ xe2 \ x80 \ x9c'. entonces si llamo 'set names latin1', el personaje se convierte en' \ xe2 \ x80 \ x93'. En PHP, va de â € "a à ¢ â'¬â € œ. Por lo tanto, tenerlo configurado en latin1 realmente lo hace funcionar bien en PHP. Estoy bastante seguro de que Django llama 'set names utf8' para preparar la conexión, en realidad. – JAL

+1

Aha, parece que necesitaba llamar 'set names' antes de insertar los datos. – JAL

+0

Insertando los datos en php, eso es. Voy a seguir adelante y aceptar su respuesta (aunque debo tener en cuenta que para los lectores futuros, la solución fue llamar 'set names utf8' para la conexión PHP, no la de Python) – JAL

0

Agregué set names utf8 a mi secuencia de inserción de datos php, y ahora en un shell de Python el temido ndash aparece como \ x96. Esto se representa correctamente cuando se lee y se envía a través de Django.

Una situación inusual sobre esto es que estoy insertando datos a través de PHP. Django emite set names utf8 automáticamente, por lo que es probable que si insertaba y leía los datos a través de Django, este problema no hubiera aparecido. PHP se utiliza el valor predeterminado de latin1, supongo

Como una nota interesante, mientras que antes de que pudiera leer los datos de PHP y se notaba con normalidad en el navegador, ahora el ndash es menos que yo llamo set names antes de leer los datos .

Por lo tanto, está funcionando ahora y espero que nunca tenga que entender lo que estaba pasando antes.

+0

Sí, eso va a ser un problema con su datos antiguos Si puede permitirse desconectar su DB por un tiempo, puede cambiar las columnas que son cadenas a latin1; luego, póngalos en blobs; luego, configúrelos de nuevo a utf8. Esto debería corregir las antiguas cadenas de doble codificación. – phsource

+0

Afortunadamente capté todo esto en la etapa de desarrollo, así que tengo la maravillosa flexibilidad de dejar caer, truncar y recrear las tablas para probar todo. Eso podría ser útil para el resto del sitio, sin embargo ... No tengo idea si tenemos otros datos que están mal codificados. Gracias por el consejo sobre cómo hacer eso. – JAL

Cuestiones relacionadas