Beim Versuch, Vorname und Nachname in Djangos auth_user-Modell zu speichern, wurde eine seltsame Fehlermeldung angezeigt.
Beispiele fehlgeschlagen
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
Erfolgreiche Beispiele
user.first_name = u'Marcin'
user.last_name = u'Król'
user.save()
>>> SUCCEED
MySQL-Einstellungen
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)
Tabellenzeichensatz und Sortierung
Die Tabelle auth_user enthält den Zeichensatz utf-8 mit der Sortierung utf8_general_ci.
Ergebnisse des UPDATE-Befehls
Beim Aktualisieren der obigen Werte in die Tabelle auth_user mit dem Befehl UPDATE wurde kein Fehler ausgegeben.
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
Die oben aufgeführten fehlgeschlagenen Werte können in die PostgreSQL-Tabelle aktualisiert werden, als ich das Datenbank-Backend in Django gewechselt habe. Es ist komisch.
mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+-----------------------------+---------------------+--------+
...
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
...
Aber von http://www.postgresql.org/docs/8.1/interactive/multibyte.html fand ich Folgendes:
Name Bytes/Char
UTF8 1-4
Bedeutet dies, dass Unicode-Zeichen in PostgreSQL maximal 4 Byte und in MySQL maximal 3 Byte haben, was den oben genannten Fehler verursacht hat?
Antworten:
Keine dieser Antworten löste das Problem für mich. Die Hauptursache ist:
Sie können keine 4-Byte-Zeichen in MySQL mit dem Zeichensatz utf-8 speichern.
MySQL hat ein 3-Byte-Limit für utf-8-Zeichen (ja, es ist verrückt, hier von einem Django-Entwickler gut zusammengefasst )
Um dies zu lösen, müssen Sie:
settings.py
Hinweis: Bei der Neuerstellung Ihrer Datenbank tritt möglicherweise das Problem " Angegebener Schlüssel war zu lang " auf.
Die wahrscheinlichste Ursache ist eine
CharField
mit einer maximalen Länge von 255 und einer Art Index (z. B. eindeutig). Da utf8mb4 33% mehr Speicherplatz als utf-8 benötigt, müssen Sie diese Felder um 33% verkleinern.Ändern Sie in diesem Fall die max_length von 255 auf 191.
Alternativ können Sie Ihre MySQL-Konfiguration bearbeiten, um diese Einschränkung zu beseitigen, jedoch nicht ohne Django-Hackery
UPDATE: Ich bin gerade wieder auf dieses Problem gestoßen und bin zu PostgreSQL gewechselt, weil ich meine
VARCHAR
Anzahl auf 191 Zeichen nicht reduzieren konnte .quelle
'charset': 'utf8mb4'
Option in den Django-Einstellungen ist kritisch, wie @Xerion sagte. Schließlich ist das Indexproblem ein Chaos. Entfernen Sie den Index für die Spalte oder machen Sie eine Länge von nicht mehr als 191 oder verwenden SieTextField
stattdessen ein!Ich hatte das gleiche Problem und löste es durch Ändern des Zeichensatzes der Spalte. Obwohl Ihre Datenbank einen Standardzeichensatz von hat
utf-8
, ist es meiner Meinung nach möglich, dass Datenbankspalten in MySQL einen anderen Zeichensatz haben. Hier ist die SQL-Abfrage, die ich verwendet habe:quelle
Wenn Sie dieses Problem haben, finden Sie hier ein Python-Skript, mit dem Sie alle Spalten Ihrer MySQL-Datenbank automatisch ändern können.
quelle
db.commit()
zuvor hinzugefügt habedb.close()
.Wenn es sich um ein neues Projekt handelt, lösche ich einfach die Datenbank und erstelle ein neues mit einem geeigneten Zeichensatz:
quelle
- --character-set-server=utf8
Ich habe nur eine Methode gefunden, um die oben genannten Fehler zu vermeiden.
In Datenbank speichern
Ist dies die einzige Methode, um solche Zeichenfolgen in einer MySQL-Tabelle zu speichern und zu dekodieren, bevor sie zur Anzeige in Vorlagen gerendert werden?
quelle
.encode('unicode_escape')
keine Unicode-Zeichen in der Datenbank speichern. Sie zwingen alle Clients, den Code zu entschlüsseln, bevor Sie sie verwenden. Dies bedeutet, dass dies mit django.admin oder allen möglichen anderen Dingen nicht ordnungsgemäß funktioniert.utf8
Zeichensatz von MySQL 5.1 zu speichern .utf8mb4
, mit der mehr als die mehrsprachige Grundebene gespeichert werden kann. Ich weiß, Sie würden denken, "UTF8" ist alles, was benötigt wird, um Unicode vollständig zu speichern. Nun, was weißt du, das ist es nicht. Siehe dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.htmlSie können die Sortierung Ihres Textfelds in UTF8_general_ci ändern, und das Problem wird behoben.
Beachten Sie, dass dies in Django nicht möglich ist.
quelle
Sie versuchen nicht, Unicode-Zeichenfolgen zu speichern, sondern Bytestrings in der UTF-8-Codierung zu speichern. Machen Sie sie zu tatsächlichen Unicode-String-Literalen:
oder (wenn Sie keine String-Literale haben) dekodieren Sie sie mit der utf-8-Codierung:
quelle
Ändern Sie einfach Ihren Tisch, Sie brauchen nichts. Führen Sie diese Abfrage einfach in der Datenbank aus. ALTER TABLE
table_name
CONVERT TO CHARACTER SET utf8es wird definitiv funktionieren.
quelle
Verbesserung der Antwort von @madprops - Lösung als Django-Verwaltungsbefehl:
Hoffe das hilft jedem außer mir :)
quelle