Проблема Юникода с SQLAlchemy - PullRequest
8 голосов
/ 08 июня 2009

Я знаю, что у меня проблема с конвертацией из Unicode, но я не уверен, где это происходит.

Я извлекаю данные о недавней поездке Eruopean из каталога файлов HTML. Некоторые из названий местоположений имеют символы не ASCII (такие как é, ô, ü). Я получаю данные из строкового представления файла с помощью регулярных выражений.

Если я печатаю местоположения так, как я их нахожу, они печатаются с символами, поэтому кодировка должна быть в порядке:

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 ]

11 голосов
/ 09 июня 2009

Я нашел эту статью, которая несколько объяснила мои проблемы:

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')

Теперь я могу запрашивать данные из таблицы и манипулировать ими без ошибок, возникших ранее. Мне просто нужно указать кодировку при выводе текста.

(Я до сих пор не совсем понимаю, как это работает, поэтому я думаю, что пришло время узнать больше об обработке Unicode Python ...)

7 голосов
/ 09 июня 2009

С sqlalchemy.org

См. Раздел 0.4.2

добавлен новый флаг в строку и create_engine (), assert _unicode = (True | False | 'warn' | None). По умолчанию False или None вкл. создать _engine () и String, 'warn' для типа Юникод. когда True, приводит ко всем операциям преобразования Unicode, поднимая исключение, когда не-Unicode Bytestring передается в качестве параметра связывания. «предупредить» результаты в предупреждении. Настоятельно рекомендуется, чтобы все Unicode-знающие Приложения правильно использовать Unicode-объекты Python (то есть u'hello ', а не 'Привет') так что данные круговорота точно.

Я думаю, вы пытаетесь ввести не-юникодную байтовую строку. Возможно, это может привести вас на правильный путь? Нужна некоторая форма конверсии, сравните «привет» и «привет».

Приветствия

7 голосов
/ 08 июня 2009

Попробуйте использовать тип столбца Unicode вместо String для столбцов 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))

Редактировать: Ответ на комментарий:

Если вы получаете предупреждения о кодировке Unicode, вы можете попробовать сделать две вещи:

  1. Преобразование вашего местоположения в Unicode. Это будет означать, что ваша точка будет создана следующим образом:

    newpoint = Точка (имя файла, pdate, ptime, юникод (местоположение), погода, высокая, низкая, широта, долгота, изображение, подпись)

    Преобразование Unicode приведет к появлению строки Unicode при передаче либо строки, либо строки Unicode, поэтому вам не нужно беспокоиться о том, что вы передаете.

  2. Если это не решает проблемы с кодировкой, попробуйте вызвать кодирование для ваших объектов Unicode. Это будет означать использование кода вроде:

    newpoint = Point (имя файла, pdate, ptime, юникод (местоположение) .encode ('utf-8'), погода, максимум, минимум, широта, долгота, изображение, заголовок)

    Этот шаг, вероятно, не понадобится, но по сути он конвертирует объект Unicode из кодовых точек Unicode в конкретное представление байтов (в данном случае, utf-8). Я ожидаю, что SQLAlchemy сделает это за вас, когда вы передадите объекты в юникоде, но это может не произойти.

...