J'ai reçu un message d'erreur étrange lorsque j'ai essayé de sauvegarder first_name, last_name dans le modèle auth_user de Django.
Exemples d'échec
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
Réussir des exemples
user.first_name = u'Marcin'
user.last_name = u'Król'
user.save()
>>> SUCCEED
Paramètres 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)
Jeu de caractères et classement de table
La table auth_user a le jeu de caractères utf-8 avec le classement utf8_general_ci.
Résultats de la commande UPDATE
Il n'a généré aucune erreur lors de la mise à jour des valeurs ci-dessus dans la table auth_user à l'aide de la commande 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
Les valeurs ayant échoué répertoriées ci-dessus peuvent être mises à jour dans la table PostgreSQL lorsque j'ai basculé le backend de la base de données dans Django. C'est étrange.
mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+-----------------------------+---------------------+--------+
...
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
...
Mais à partir de http://www.postgresql.org/docs/8.1/interactive/multibyte.html , j'ai trouvé ce qui suit:
Name Bytes/Char
UTF8 1-4
Est-ce que cela signifie que le caractère unicode a maxlen de 4 octets dans PostgreSQL mais 3 octets dans MySQL qui a causé l'erreur ci-dessus?
Réponses:
Aucune de ces réponses n'a résolu le problème pour moi. La cause première étant:
Vous ne pouvez pas stocker des caractères de 4 octets dans MySQL avec le jeu de caractères utf-8.
MySQL a une limite de 3 octets sur les caractères utf-8 (oui, c'est wack, bien résumé par un développeur Django ici )
Pour résoudre ce problème, vous devez:
settings.py
Remarque: lors de la recréation de votre base de données, vous pouvez rencontrer le message `` La clé spécifiée était trop longue problème «La ».
La cause la plus probable est un
CharField
qui a une longueur_max de 255 et une sorte d'index dessus (par exemple, unique). Comme utf8mb4 utilise 33% d'espace en plus que utf-8, vous devrez réduire ces champs de 33%.Dans ce cas, modifiez max_length de 255 à 191.
Alternativement, vous pouvez modifier votre configuration MySQL pour supprimer cette restriction, mais pas sans un piratage django
MISE À JOUR: Je viens de rencontrer à nouveau ce problème et j'ai fini par passer à PostgreSQL car je ne pouvais pas réduire mon
VARCHAR
à 191 caractères.la source
'charset': 'utf8mb4'
option dans les paramètres Django est également essentielle, comme l'a dit @Xerion. Enfin, le problème d'index est un gâchis. Supprimez l'index de la colonne, ou ne faites pas plus que 191, ou utilisez un à laTextField
place!J'ai eu le même problème et je l'ai résolu en modifiant le jeu de caractères de la colonne. Même si votre base de données a un jeu de caractères par défaut,
utf-8
je pense qu'il est possible que les colonnes de base de données aient un jeu de caractères différent dans MySQL. Voici la requête SQL que j'ai utilisée:la source
Si vous rencontrez ce problème, voici un script python pour changer automatiquement toutes les colonnes de votre base de données mysql.
la source
db.commit()
avantdb.close()
.S'il s'agit d'un nouveau projet, je supprimerais simplement la base de données et en créerais une nouvelle avec un jeu de caractères approprié:
la source
- --character-set-server=utf8
Je viens de trouver une méthode pour éviter les erreurs ci-dessus.
Enregistrer dans la base de données
Est-ce la seule méthode pour enregistrer des chaînes comme celle-ci dans une table MySQL et la décoder avant de la rendre dans des modèles pour l'affichage?
la source
.encode('unicode_escape')
ne stockez pas réellement de caractères Unicode dans la base de données. Vous obligez tous les clients à désencoder avant de les utiliser, ce qui signifie que cela ne fonctionnera pas correctement avec django.admin ou toutes sortes d'autres choses.utf8
.utf8mb4
qui permet de stocker plus que le plan multilingue de base. Je sais, vous penseriez que "UTF8" est tout ce dont vous avez besoin pour stocker entièrement Unicode. Eh bien, whaddaya sais, ce n'est pas le cas. Voir dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.htmlVous pouvez changer le classement de votre champ de texte en UTF8_general_ci et le problème sera résolu.
Remarquez que cela ne peut pas être fait dans Django.
la source
Vous n'essayez pas de sauvegarder des chaînes Unicode, vous essayez de sauvegarder des chaînes d'octets dans l'encodage UTF-8. Faites-en de véritables littéraux de chaîne Unicode:
ou (lorsque vous n'avez pas de littéraux de chaîne) décodez-les en utilisant l'encodage utf-8:
la source
Modifiez simplement votre table, pas besoin de quoi que ce soit. exécutez simplement cette requête sur la base de données. ALTER TABLE
table_name
CONVERT TO CARACTER SET utf8cela fonctionnera certainement.
la source
Amélioration de la réponse @madprops - solution en tant que commande de gestion django:
J'espère que cela aide tout le monde sauf moi :)
la source