我遇到过这样的错误:
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)
当我试图用指定的Python unicode
字符串保存ORM对象时,会发生这种情况。因此,dict
parameters
将unicode字符串作为其值之一,并在将其强制转换为str
类型时产生错误。
我尝试在引擎和列上设置convert_unicode=True
设置,但没有成功。
那么在SQLAlchemy中处理unicode的好方法是什么?
这是关于我的设置的一些细节:
表格
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设置:
ENGINE = create_engine('postgresql://me:secret@localhost/my_db',
encoding='utf8', convert_unicode=True)
Session = sessionmaker(bind=ENGINE)
产生错误的代码只是创建一个会话,实例化一个Document
对象并使用分配给它的source
字段with
unicode` strign保存它。
检查this repo - 它已自动设置Vagrant / Ansible,并重现此错误。
答案 0 :(得分:10)
你的问题在这里:
$ 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')
我推荐前者,因为九十年代初期早已不复存在。 :)
答案 1 :(得分:3)
我无法重现您的问题(您也没有包含有关如何将项目实际添加到数据库中的示例,可能存在错误)。但是,我建议您在与系统的其余部分完全隔离的情况下测试代码,以查看您想要执行的操作是否真正有效,而不会受到其他代码的干扰。我创建这个文件只是为了测试你想做什么,并且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。
答案 2 :(得分:0)
我无法重现您的错误。我可以提供一些关于使用SQLAlchemy进行unicode处理的提示,这些技巧可能会有所帮助,也可能没有帮助:
convert_unicode
,而只使用sqlalchemy.types.Unicode()列类型。这将永远是正确的。'key'
,也要将str实例(key
)分配给convert_unicode=True
列。您要么指定unicode值,要么使用非unicode代码列类型。encoding
和convert_unicode
参数。