Komunikat o błędzie
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2026'
in position 35: ordinal not in range(256)
wydaje się wskazywać, że jakiś kod języka Python próbuje przekonwertować znak \u2026
do łańcucha Latin-1 (ISO8859-1) i nie działa. Nic dziwnego, że ten znak to U+2026 POZIOMA ELIPSA
, który nie ma jednego odpowiednika w ISO8859-1.
Naprawiłeś problem, dodając zapytanie ?charset=utf8
w wywołaniu połączenia SQLAlchemy:
import sqlalchemy
from sqlalchemy import create_engine, MetaData, Table
db = create_engine('mysql://user:[email protected]/db?charset=utf8')
Sekcja URL bazy danych
dokumentacji SQLAlchemy mówi nam, że adres URL zaczynający się od mysql
wskazuje dialekt MySQL, używając mysql-python
kierowca.
Poniższa sekcja, Niestandardowe DBAPI argumenty connect() , informuje nas, że argumenty zapytania są przekazywane do bazowego DBAPI.
Co więc oznacza mysql-python
wykonanie sterownika z parametrem {charset:'utf8'}
? Sekcja Funkcje i atrybuty
ich dokumentacji mówi o zestawie znaków
atrybut "...Jeśli jest obecny, zestaw znaków połączenia zostanie zmieniony na ten zestaw znaków, jeśli nie są one równe."
Aby dowiedzieć się, co oznacza zestaw znaków połączenia, zwracamy się do 10.1.4. Zestawy znaków połączenia i sortowanie podręcznika MySQL 5.6. Krótko mówiąc, MySQL może interpretować przychodzące zapytania jako kodowanie inne niż zestaw znaków bazy danych i inne niż kodowanie zwróconych wyników zapytania.
Ponieważ zgłoszony komunikat o błędzie wygląda jak komunikat o błędzie Pythona, a nie SQL, będę spekulować, że coś w SQLAlchemy lub mysql-python próbuje przekonwertować zapytanie na domyślne kodowanie połączenia latin-1
przed wysłaniem. To jest przyczyną błędu. Jednak ciąg zapytania ?charset=utf8
w swoim connect()
wywołanie zmienia kodowanie połączenia, a U+2026 HORIZONTAL ELIPSIS
jest w stanie się przedostać.
Aktualizacja: pytasz również:„Jeśli usunę opcję zestawu znaków, a następnie zakoduję opis za pomocą .encode('cp1252'), wszystko będzie dobrze. Jak wielokropek może przejść przez cp1252, ale nie Unicode?”
kodowanie cp1252
ma
poziomy znak wielokropka o wartości bajtu \x85
. W ten sposób można zakodować ciąg znaków Unicode zawierający U+2026 POZIOMA WIELOKROTKA
do cp1252 bez błędu.
Pamiętaj też, że w Pythonie łańcuchy Unicode i łańcuchy bajtów to dwa różne typy danych. Rozsądne jest spekulowanie, że MySQLdb może mieć politykę wysyłania tylko ciągów bajtów przez połączenie SQL. W ten sposób zakoduje zapytanie odebrane jako ciąg Unicode w ciągu bajtów, ale pozostawi zapytanie odebrane jako ciąg bajtów. (To spekulacje, nie zajrzałem do kodu źródłowego.)
W przesłanym przez Ciebie śledzeniu, ostatnie dwie linie (najbliżej miejsca wystąpienia błędu) pokazują nazwy metod literal
, po którym następuje unicode_literal
. To potwierdza teorię, że MySQLdb koduje zapytanie, które otrzymuje jako ciąg Unicode w ciąg bajtów.
Kiedy sam kodujesz ciąg zapytania, pomijasz część MySQLdb, która wykonuje to kodowanie w inny sposób. Pamiętaj jednak, że jeśli zakodujesz ciąg zapytania w inny sposób, niż wymaga tego zestaw znaków połączenia MySQL, będziesz mieć niezgodność w kodowaniu, a tekst prawdopodobnie będzie zapisany nieprawidłowo.