tmr*_*lvi 7 postgresql unicode sqlalchemy python-2.x
我正在使用postgres/SQLAlchemy/Flask-Admin开发Flask应用程序.但是,在Admin界面中,自unicode(exc)提升以来,无法报告包含Unicode字母的任何DB错误UnicodeDecodeError.
我找到了那个问题 sqlalchemy.exc
class StatementError(SQLAlchemyError):
...
def __unicode__(self):
return self.__str__()
Run Code Online (Sandbox Code Playgroud)
并通过以下方式重现问题:
class A(Base):
__tablename__="a"
id = Column(Integer, primary_key=True)
name = Column(String)
name2 = Column(String, nullable=False)
session = Session()
a = A(name=u"?????")
session.add(a)
try:
session.commit()
except Exception as e:
print(repr(e))
print("------------------")
print(unicode(e))
Run Code Online (Sandbox Code Playgroud)
哪个回报:
ProgrammingError('(psycopg2.ProgrammingError) column "name" of relation "a" does not exist\nLINE 1: INSERT INTO a (name, name2) VALUES (\'\xd7\xa2\xd7\x91\xd7\xa8\xd7\x99\xd7\xaa\', NULL) RETURNING...\n ^\n',)
------------------
Traceback (most recent call last):
File "test.py", line 27, in <module>
print(unicode(e))
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd7 in position 118: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)
我目前通过用我的解码方法替换相关的异常来解决它utf-8.然而,这是一个可怕的黑客,我正在寻找一个合适的解决方案:
latin编码方式输出消息(不太有利,但可以加入)unicode尝试解码utf-8而不是ascii/ latin?(这个问题只与Python2有关.在Python3中,上面的代码可以工作.我相信这是因为默认编码是utf-8)
实际上,我认为从应用程序中修补 SQLAlchemy 是正确且相当干净的解决方案。原因如下:
您已经发现了一些通常被认为是 SQLAlchemy 中的错误的东西。
您可以编写一个补丁,该补丁对于 SQLAlchemy 当前使用的所有情况都具有相同的行为。也就是说,您的补丁不会破坏现有代码
即使修复了 SQLAlchemy,您的补丁也很有可能是无害的。
与更改可能打印异常的每个位置等解决方案相比,进行此更改可以减少 SQLAlchemy 错误对整个代码的影响。
更改 PostGres 以返回 latin1 编码实际上没有帮助,因为 python 使用 ascii 编码,当给定 latin1 字符串时,这会给出相同的错误。此外,更改 PostGres 以返回 latin1 错误可能会涉及更改连接编码;这可能会给 unicode 数据带来问题。
这是一个简单的程序,用于修补 sqlalchemy.exc.StatementError 并测试该补丁。如果您愿意,您甚至可以尝试生成包含 unicode 的异常,将其转换为 unicode,并且仅在引发 UnicodeDecodeError 时才应用补丁。如果您这样做,当 sqlalchemy 修复问题时,您的补丁将自动停止应用。
# -*- coding: utf-8 -*-
from sqlalchemy.exc import StatementError
def statement_error_unicode(self):
return unicode(str(self), 'utf-8')
# See <link to sqlalchemy issue>; can be removed once we require a
# version of sqlalchemy with a fix to that issue
StatementError.__unicode__ = statement_error_unicode
message = u'Sqlalchemy unicode '
message_str = message.encode('utf-8')
error = StatementError(message_str, 'select * from users', tuple(), '')
print unicode(error)
Run Code Online (Sandbox Code Playgroud)