Как сохранить unicode с помощью SQLAlchemy?
я столкнулся с такой ошибкой:
File "/vagrant/env/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 435, in do_execute
cursor.execute(statement, parameters)
exceptions.UnicodeEncodeError: 'ascii' codec can't encode character u'u2013' in position 8410: ordinal not in range(128)
это происходит, когда я пытаюсь сохранить объект ORM с назначенным Python unicode
строку. И в результате dict
parameters
имеет строку unicode в качестве одного из своих значений, и она создает ошибку, принуждая ее к str
тип.
я пытался установить convert_unicode=True
установка на двигатель и колонку, но без успеха.
Итак, каков хороший способ обработки unicode в С SQLAlchemy?
обновление
это некоторые подробности о моей установке:
стол:
Table "public.documents"
Column | Type | Modifiers
------------+--------------------------+--------------------------------------------------------
id | integer | not null default nextval('documents_id_seq'::regclass)
sha256 | text | not null
url | text |
source | text | not null
downloaded | timestamp with time zone | not null
tags | json | not null
Indexes:
"documents_pkey" PRIMARY KEY, btree (id)
"documents_sha256_key" UNIQUE CONSTRAINT, btree (sha256)
модель ORM:
class Document(Base):
__tablename__ = 'documents'
id = Column(INTEGER, primary_key=True)
sha256 = Column(TEXT(convert_unicode=True), nullable=False, unique=True)
url = Column(TEXT(convert_unicode=True))
source = Column(TEXT(convert_unicode=True), nullable=False)
downloaded = Column(DateTime(timezone=True), nullable=False)
tags = Column(JSON, nullable=False)
SQLAlchemy settngs:
ENGINE = create_engine('postgresql://me:secret@localhost/my_db',
encoding='utf8', convert_unicode=True)
Session = sessionmaker(bind=ENGINE)
и код, который создает ошибку, просто создает сеанс, создает экземпляр Document
объект и сохраняет его с source
полеwith
unicode ' strign назначен ему.
обновление #2
Регистрация этой repo-он имеет автоматическую настройку Vagrant/Ansible и воспроизводит эту ошибку.
3 ответов
ваша проблема здесь:
$ sudo grep client_encoding /etc/postgresql/9.3/main/postgresql.conf
client_encoding = sql_ascii
это заставляет psycopg2 по умолчанию использовать ASCII:
>>> import psycopg2
>>> psycopg2.connect('dbname=dev_db user=dev').encoding
'SQLASCII'
... что эффективно отключает способность psycopg2 обрабатывать Unicode.
вы можете исправить это в PostgreSQL.conf:
client_encoding = utf8
(затем sudo invoke-rc.d postgresql reload
), или вы можете указать кодировку явно при создании движка:
self._conn = create_engine(src, client_encoding='utf8')
я рекомендую первое, потому что начало девяностых давно прошло. : )
Я не могу воспроизвести вашу проблему (также вы не включили примеры того, как вы фактически добавляете свои элементы в базу данных, ошибка может быть там). Однако я рекомендую вам протестировать свой код в полной изоляции с остальной частью вашей системы, чтобы увидеть, действительно ли то, что вы хотите сделать, работает без вмешательства вашего другого кода. Я создал этот файл исключительно для проверки того, работает ли то, что вы хотите сделать, и метод main вставил соответствующий объект в строку база данных.
# encoding: utf-8
from sqlalchemy import Column, Integer, String, Boolean, Float, Text
from sqlalchemy import Column, INTEGER, TEXT
from sqlalchemy import create_engine, MetaData
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class Demo(Base):
__tablename__ = 'demo'
id = Column(INTEGER, primary_key=True)
key = Column(TEXT(convert_unicode=True))
value = Column(TEXT(convert_unicode=True))
class Backend(object):
def __init__(self, src=None):
if not src:
src = 'sqlite://'
self._conn = create_engine(src)
self._metadata = MetaData()
self._metadata.reflect(bind=self._conn)
Base.metadata.create_all(self._conn)
self._sessions = sessionmaker(bind=self._conn)
def session(self):
return self._sessions()
def main():
backend = Backend('postgresql://postgres@localhost/test')
s = backend.session()
obj = Demo()
obj.key = 'test'
obj.value = u'–test–'
s.add(obj)
s.commit()
return backend
запуск этого внутри переводчика:
>>> b = main()
>>> s = b.session()
>>> s.query(Demo).get(1).value
u'\u2013test\u2013'
и в psql в:
postgres=# \c test
You are now connected to database "test" as user "postgres".
test=# select * from demo;
id | key | value
----+------+--------
1 | test | –test–
(1 row)
Извините, что я не смог вам помочь, но я надеюсь, что это укажет вам (или кому-то еще) на то, почему ваш код получает ошибку декодирования unicode. Версии программного обеспечения, которое я использовал,-python-2.7.7, sqlalchemy-0.9.6, psycopg2-2.5.3, postgresql-9.3.4.
Я не могу воспроизвести вашу ошибку. Я могу предоставить несколько советов по обработке unicode с помощью SQLAlchemy, которые могут помочь или не помочь:
- вместо
convert_unicode
просто используйте sqlalchemy.типы.Юникод() тип столбца. Это всегда будет правильно. - вы назначаете экземпляр str (
'key'
) к