Recebi uma mensagem de erro estranha ao tentar salvar first_name, last_name no modelo auth_user do Django.
Exemplos com falha
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
Exemplos de sucesso
user.first_name = u'Marcin'
user.last_name = u'Król'
user.save()
>>> SUCCEED
Configurações do 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 e agrupamento de tabelas
A tabela auth_user possui utf-8 charset com agrupamento utf8_general_ci.
Resultados do comando UPDATE
Não gerou nenhum erro ao atualizar os valores acima para a tabela auth_user usando o 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
Os valores com falha listados acima podem ser atualizados na tabela do PostgreSQL quando eu mudei o back-end do banco de dados no Django. É estranho.
mysql> SHOW CHARACTER SET;
+----------+-----------------------------+---------------------+--------+
| Charset | Description | Default collation | Maxlen |
+----------+-----------------------------+---------------------+--------+
...
| utf8 | UTF-8 Unicode | utf8_general_ci | 3 |
...
Mas em http://www.postgresql.org/docs/8.1/interactive/multibyte.html , encontrei o seguinte:
Name Bytes/Char
UTF8 1-4
Isso significa que o unicode char possui no máximo 4 bytes no PostgreSQL, mas 3 bytes no MySQL, o que causou um erro acima?
Respostas:
Nenhuma dessas respostas resolveu o problema para mim. A causa raiz é:
Você não pode armazenar caracteres de 4 bytes no MySQL com o conjunto de caracteres utf-8.
O MySQL tem um limite de 3 bytes em caracteres utf-8 (sim, é maluco, bem resumido por um desenvolvedor do Django aqui )
Para resolver isso, você precisa:
settings.py
Nota: Ao recriar seu banco de dados, você pode executar o problema 'A chave especificada era muito longa '.
A causa mais provável é uma
CharField
que tenha um comprimento máximo de 255 e algum tipo de índice (por exemplo, exclusivo). Como o utf8mb4 usa 33% mais espaço que o utf-8, você precisará tornar esses campos 33% menores.Nesse caso, altere o max_length de 255 para 191.
Como alternativa, você pode editar sua configuração do MySQL para remover essa restrição, mas não sem algum hackery do django
ATUALIZAÇÃO: Acabei de encontrar esse problema novamente e acabei migrando para o PostgreSQL porque não consegui reduzir meus
VARCHAR
191 caracteres.fonte
'charset': 'utf8mb4'
opção nas configurações do Django é crítica, como disse o @Xerion. Finalmente, o problema do índice está uma bagunça. Remova o índice na coluna, ou faça seu comprimento não superior a 191, ou use umTextField
!Eu tive o mesmo problema e resolvi-o alterando o conjunto de caracteres da coluna. Mesmo que seu banco de dados tenha um conjunto de caracteres padrão,
utf-8
acho que é possível que as colunas do banco de dados tenham um conjunto de caracteres diferente no MySQL. Aqui está o SQL QUERY que eu usei:fonte
Se você tiver esse problema, aqui está um script python para alterar todas as colunas do seu banco de dados mysql automaticamente.
fonte
db.commit()
antesdb.close()
.Se for um novo projeto, basta soltar o banco de dados e criar um novo com um conjunto de caracteres adequado:
fonte
- --character-set-server=utf8
Eu apenas descobri um método para evitar os erros acima.
Salvar no banco de dados
Esse é o único método para salvar seqüências de caracteres como essa em uma tabela MySQL e decodificá-la antes de renderizar em modelos para exibição?
fonte
.encode('unicode_escape')
não está realmente armazenando caracteres unicode no banco de dados. Você está forçando todos os clientes a descriptografar antes de usá-los, o que significa que não funcionará corretamente com o django.admin ou com qualquer outra coisa.utf8
conjunto de caracteres de 3 bytes do MySQL 5.1 .utf8mb4
que permite que mais do que o plano multilíngue básico seja armazenado. Eu sei, você pensaria que "UTF8" é tudo o que é necessário para armazenar totalmente o Unicode. Bem, como você sabe, não é. Veja dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.htmlVocê pode alterar o agrupamento do seu campo de texto para UTF8_general_ci e o problema será resolvido.
Observe que isso não pode ser feito no Django.
fonte
Você não está tentando salvar seqüências de caracteres unicode, mas também está tentando salvar cadeias de caracteres na codificação UTF-8. Torne-os literais reais de cadeias unicode:
ou (quando você não possui literais de string) decodifique-os usando a codificação utf-8:
fonte
Simplesmente altere sua mesa, sem necessidade de nada. basta executar esta consulta no banco de dados. ALTER TABLE
table_name
CONVERT TO CHARACTER SET utf8definitivamente funcionará.
fonte
Melhoria na resposta @madprops - solution como um comando de gerenciamento do django:
Espero que isso ajude alguém, exceto eu :)
fonte