Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Como faço para que o SQLAlchemy insira corretamente reticências unicode em uma tabela mySQL?


A mensagem de erro
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2026' 
in position 35: ordinal not in range(256)

parece indicar que algum código da linguagem Python está tentando converter o caractere \u2026 em uma string Latin-1 (ISO8859-1) e está falhando. Sem surpresa, esse caractere é U+2026 HORIZONTAL ELLIPSIS , que não possui um único caractere equivalente em ISO8859-1.

Você corrigiu o problema adicionando a consulta ?charset=utf8 em sua chamada de conexão SQLAlchemy:
import sqlalchemy
from sqlalchemy import create_engine, MetaData, Table

db = create_engine('mysql://user:[email protected]/db?charset=utf8')

A seção URls do banco de dados da documentação do SQLAlchemy nos diz que uma URL começando com mysql indica um dialeto MySQL, usando o mysql-python motorista.

A seção a seguir, DBAPI personalizada argumentos connect() , nos informa que os argumentos de consulta são passados ​​para a DBAPI subjacente.

Então, o que o mysql-python driver make de um parâmetro {charset:'utf8'} ? Seção Funções e atributos de sua documentação diz do charset atributo "...Se presente, o conjunto de caracteres de conexão será alterado para este conjunto de caracteres, se não forem iguais."

Para descobrir o que significa o conjunto de caracteres de conexão, vamos para 10.1.4. Conjuntos de caracteres de conexão e agrupamentos do manual de referência do MySQL 5.6. Para encurtar a história, o MySQL pode interpretar as consultas recebidas como uma codificação diferente do conjunto de caracteres do banco de dados e diferente da codificação dos resultados da consulta retornada.

Como a mensagem de erro que você relatou se parece com um Python em vez de uma mensagem de erro SQL, especularei que algo em SQLAlchemy ou mysql-python está tentando converter a consulta em uma codificação de conexão padrão de latin-1 antes de enviá-lo. Isso é o que desencadeia o erro. No entanto, a string de consulta ?charset=utf8 em seu connect() A chamada altera a codificação da conexão e a U+2026 HORIZONTAL ELLIPSIS é capaz de passar.

Atualização: você também pergunta, "se eu remover a opção charset e, em seguida, codificar a descrição usando .encode('cp1252'), ela passará bem. Como uma reticência é capaz de passar com cp1252, mas não com unicode?"

A codificação cp1252 tem um caractere de reticências horizontais no valor de byte \x85 . Assim é possível codificar uma string Unicode contendo U+2026 HORIZONTAL ELLIPSIS em cp1252 sem erro.

Lembre-se também que em Python, strings Unicode e strings de bytes são dois tipos de dados diferentes. É razoável especular que o MySQLdb pode ter uma política de enviar apenas strings de bytes em uma conexão SQL. Assim, ele codificaria uma consulta recebida como uma string Unicode em uma string de bytes, mas deixaria uma consulta recebida como uma string de bytes sozinha. (Isso é especulação, eu não olhei para o código-fonte.)

No traceback que você postou, as duas últimas linhas (mais próximas de onde ocorre o erro) mostram os nomes dos métodos literal , seguido por unicode_literal . Isso tende a apoiar a teoria de que o MySQLdb está codificando a consulta que recebe como uma string Unicode em uma string de bytes.

Quando você codifica a string de consulta, você ignora a parte do MySQLdb que faz essa codificação de maneira diferente. Observe, no entanto, que se você codificar a string de consulta de maneira diferente do que o conjunto de caracteres de conexão do MySQL chama, você terá uma incompatibilidade de codificação e seu texto provavelmente será armazenado incorretamente.