Проблема с Юникод с SQLAlchemy
Я знаю, что у меня проблема с преобразованием из Unicode, но я не уверен, где это происходит.
Я извлечение данных о недавнем Eruopean поездка из каталога HTML-файлов. Некоторые из названий местоположений имеют символы, отличные от ASCII (например, é, ô, ü). Я получаю данные из строкового представления файла с помощью regex.
если я печатаю местоположения, как я их нахожу, они печатают с символами, поэтому кодировка должна быть ok:
Le Pré-Saint-Gervais, France
Hôtel-de-Ville, France
Я храню данные в таблице SQLite с помощью SQLAlchemy:
Base = declarative_base()
class Point(Base):
__tablename__ = 'points'
id = Column(Integer, primary_key=True)
pdate = Column(Date)
ptime = Column(Time)
location = Column(Unicode(32))
weather = Column(String(16))
high = Column(Float)
low = Column(Float)
lat = Column(String(16))
lon = Column(String(16))
image = Column(String(64))
caption = Column(String(64))
def __init__(self, filename, pdate, ptime, location, weather, high, low, lat, lon, image, caption):
self.filename = filename
self.pdate = pdate
self.ptime = ptime
self.location = location
self.weather = weather
self.high = high
self.low = low
self.lat = lat
self.lon = lon
self.image = image
self.caption = caption
def __repr__(self):
return "<Point('%s','%s','%s')>" % (self.filename, self.pdate, self.ptime)
engine = create_engine('sqlite:///:memory:', echo=False)
Base.metadata.create_all(engine)
Session = sessionmaker(bind = engine)
session = Session()
Я просматриваю файлы и вставляю данные из каждого в базу данных:
for filename in filelist:
# open the file and extract the information using regex such as:
location_re = re.compile("<h2>(.*)</h2>",re.M)
# extract other data
newpoint = Point(filename, pdate, ptime, location, weather, high, low, lat, lon, image, caption)
session.add(newpoint)
session.commit()
Я вижу следующее предупреждение на каждой вставить:
/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/default.py:230: SAWarning: Unicode type received non-unicode bind param value 'Spitalfields, United Kingdom'
param.append(processors[key](compiled_params[key]))
и когда я пытаюсь сделать что-нибудь с таблицей, например:
session.query(Point).all()
Я:
Traceback (most recent call last):
File "./extract_trips.py", line 131, in <module>
session.query(Point).all()
File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/orm/query.py", line 1193, in all
return list(self)
File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/orm/query.py", line 1341, in instances
fetch = cursor.fetchall()
File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/base.py", line 1642, in fetchall
self.connection._handle_dbapi_exception(e, None, None, self.cursor, self.context)
File "/usr/lib/python2.5/site-packages/SQLAlchemy-0.5.4p2-py2.5.egg/sqlalchemy/engine/base.py", line 931, in _handle_dbapi_exception
raise exc.DBAPIError.instance(statement, parameters, e, connection_invalidated=is_disconnect)
sqlalchemy.exc.OperationalError: (OperationalError) Could not decode to UTF-8 column 'points_location' with text 'Le Pré-Saint-Gervais, France' None None
Я хотел бы иметь возможность правильно хранить, а затем возвращать имена местоположений с помощью оригинальные персонажи целы. Любая помощь будет высоко ценится.
3 ответов
Я нашел эту статью, которая помогла немного объяснить мои проблемы:
http://www.amk.ca/python/howto/unicode#reading-and-writing-unicode-data
я смог получить желаемые результаты, используя модуль "кодеки", а затем изменив свою программу следующим образом:
при открытии файла:
infile = codecs.open(filename, 'r', encoding='iso-8859-1')
при печати местоположение:
print location.encode('ISO-8859-1')
теперь я могу запрашивать и манипулировать данными из таблицы без ошибок из прошлого. Мне просто нужно указать кодировку при выводе текста.
(я все еще не совсем понимаю, как это работает, поэтому я думаю, что пришло время узнать больше об обработке Юникода Python...)
см. раздел 0.4.2
добавлен новый флаг в строку и create_engine(), assert _unicode=(True|False|'warn'|None). По умолчанию:
False
илиNone
на создать _engine() и строку'warn'
на типе Unicode. КогдаTrue
, результаты всех операций преобразования unicode исключение, когда не-unicode bytestring передается как параметр bind. результаты "warn" в качестве предупреждения. Настоятельно рекомендуется, чтобы все unicode-aware приложения правильно использовать объекты Python unicode (т. е. u'Hello', а не "привет") так что данные туда и обратно точно.
Я думаю, вы пытаетесь ввести не-unicode bytestring. Может быть, это приведет вас на верный путь? Нужна какая-то форма преобразования, сравните "hello" и "u'Hello".
Ура
попробуйте использовать тип столбца Unicode, а не строку для столбцов unicode:
Base = declarative_base()
class Point(Base):
__tablename__ = 'points'
id = Column(Integer, primary_key=True)
pdate = Column(Date)
ptime = Column(Time)
location = Column(Unicode(32))
weather = Column(String(16))
high = Column(Float)
low = Column(Float)
lat = Column(String(16))
lon = Column(String(16))
image = Column(String(64))
caption = Column(String(64))
Edit: ответ на комментарий:
Если вы получаете предупреждения о кодировках unicode, то есть две вещи, которые вы можете попробовать:
-
преобразуйте свое местоположение в unicode. Это означало бы, что ваша точка зрения создана следующим образом:
newpoint = точка (имя файла, pdate, ptime, unicode (местоположение), погода, высокая, низкая, lat, lon, изображение, подпись)
преобразование unicode создаст строку unicode при передаче строки или строки unicode, поэтому вам не нужно беспокоиться о том, что вы передаете.
-
Если это не решает проблемы кодирования, попробуйте вызвать кодирование для объектов unicode. Это означало бы использование кода типа:
newpoint = Point(имя файла, pdate, ptime, unicode (расположение).кодирование ('utf-8'), погода, высокая, низкая, лат, Лон, изображение, подпись)
этот шаг, вероятно, не будет необходим, но по существу он преобразует объект unicode из кодовых точек unicode в конкретное байтовое представление (в этом случае utf-8). Я ожидал бы, что SQLAlchemy сделает это для вас, когда вы передадите объекты unicode, но это может быть не так.