Recibí un extraño mensaje de error cuando intenté guardar first_name, last_name en el modelo auth_user de Django.
Ejemplos fallidos
user = User.object.create_user(username, email, password)
user.first_name = u'Rytis'
user.last_name = u'Slatkevičius'
user.save()
>>> Incorrect string value: '\xC4\x8Dius' for column 'last_name' at row 104
user.first_name = u'Валерий'
user.last_name = u'Богданов'
user.save()
>>> Incorrect string value: '\xD0\x92\xD0\xB0\xD0\xBB...' for column 'first_name' at row 104
user.first_name = u'Krzysztof'
user.last_name = u'Szukiełojć'
user.save()
>>> Incorrect string value: '\xC5\x82oj\xC4\x87' for column 'last_name' at row 104
Ejemplos de éxito
user.first_name = u'Marcin'
user.last_name = u'Król'
user.save()
>>> SUCCEED
Configuración de MySQL
mysql> show variables like 'char%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
Conjunto de caracteres de tabla y colación
La tabla auth_user tiene un conjunto de caracteres utf-8 con la clasificación utf8_general_ci.
Resultados del comando ACTUALIZAR
No generó ningún error al actualizar los valores anteriores a la tabla auth_user mediante el comando UPDATE.
mysql> update auth_user set last_name='Slatkevičiusa' where id=1;
Query OK, 1 row affected, 1 warning (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select last_name from auth_user where id=100;
+---------------+
| last_name |
+---------------+
| Slatkevi?iusa |
+---------------+
1 row in set (0.00 sec)
PostgreSQL
Los valores fallidos enumerados anteriormente se pueden actualizar en la tabla PostgreSQL cuando cambié el backend de la base de datos en Django. Es extraño.
mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+-----------------------------+---------------------+--------+
...
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
...
Pero en http://www.postgresql.org/docs/8.1/interactive/multibyte.html , encontré lo siguiente:
Name Bytes/Char
UTF8 1-4
¿Significa que unicode char tiene un máximo de 4 bytes en PostgreSQL pero 3 bytes en MySQL que causó el error anterior?
Respuestas:
Ninguna de estas respuestas resolvió el problema para mí. La causa raíz es:
No puede almacenar caracteres de 4 bytes en MySQL con el conjunto de caracteres utf-8.
MySQL tiene un límite de 3 bytes en los caracteres utf-8 (sí, es wack, resumido muy bien por un desarrollador de Django aquí )
Para resolver esto necesitas:
settings.py
Nota: Al recrear su base de datos, puede encontrarse con el problema 'La clave especificada fue demasiado larga '.
La causa más probable es una
CharField
que tiene una longitud máxima de 255 y algún tipo de índice (por ejemplo, único). Como utf8mb4 usa un 33% más de espacio que utf-8, necesitará hacer que estos campos sean un 33% más pequeños.En este caso, cambie la longitud máxima de 255 a 191.
Alternativamente, puede editar su configuración de MySQL para eliminar esta restricción, pero no sin algún hacker de django
ACTUALIZACIÓN: Acabo de encontrarme con este problema nuevamente y terminé cambiando a PostgreSQL porque no pude reducir mi
VARCHAR
a 191 caracteres.fuente
'charset': 'utf8mb4'
opción en la configuración de Django es crítica, como dijo @Xerion. Finalmente, el problema del índice es un desastre. ¡Elimine el índice en la columna, o haga que su longitud no sea superior a 191, o use unTextField
en su lugar!Tuve el mismo problema y lo resolví cambiando el conjunto de caracteres de la columna. Aunque su base de datos tiene un conjunto de caracteres predeterminado
utf-8
, creo que es posible que las columnas de la base de datos tengan un conjunto de caracteres diferente en MySQL. Aquí está la consulta SQL que utilicé:fuente
Si tiene este problema, aquí hay un script de Python para cambiar todas las columnas de su base de datos mysql automáticamente.
fuente
db.commit()
antesdb.close()
.Si es un proyecto nuevo, simplemente dejaría caer la base de datos y crearía una nueva con un juego de caracteres adecuado:
fuente
- --character-set-server=utf8
Acabo de descubrir un método para evitar los errores anteriores.
Guardar en la base de datos
¿Es este el único método para guardar cadenas como esa en una tabla MySQL y decodificarla antes de renderizar en plantillas para mostrar?
fuente
.encode('unicode_escape')
realidad no está almacenando caracteres Unicode en la base de datos. Estás obligando a todos los clientes a que se descodifiquen antes de usarlos, lo que significa que no funcionará correctamente con django.admin o todo tipo de otras cosas.utf8
conjunto de caracteres de 3 bytes de MySQL 5.1 .utf8mb4
que permite almacenar más que el plano multilingüe básico. Lo sé, pensarías que "UTF8" es todo lo que se necesita para almacenar Unicode por completo. Bueno, ya sabes, no lo es. Ver dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.htmlPuede cambiar la clasificación de su campo de texto a UTF8_general_ci y el problema se resolverá.
Tenga en cuenta que esto no se puede hacer en Django.
fuente
No está intentando guardar cadenas Unicode, está intentando guardar cadenas de bytes en la codificación UTF-8. Conviértelos en literales de cadena Unicode reales
o (cuando no tiene literales de cadena) decodifíquelos usando la codificación utf-8:
fuente
Simplemente modifique su mesa, sin necesidad de nada. simplemente ejecute esta consulta en la base de datos. ALTERAR TABLA
table_name
CONVERTIR AL CARACTER SET utf8Definitivamente funcionará.
fuente
Mejora a la respuesta @madprops: solución como un comando de gestión de django:
Espero que esto ayude a cualquiera menos a mí :)
fuente