【问题标题】:SQLAlchemy Unicode Problems in Exceptions异常中的 SQLAlchemy Unicode 问题
【发布时间】:2017-09-19 20:56:38
【问题描述】:

我正在使用 postgres/SQLAlchemy/Flask-Admin 开发 Flask 应用程序。但是,在管理界面中,由于unicode(exc) 引发了UnicodeDecodeError,因此无法报告任何包含 Unicode 字母的 DB 错误。

我能够将问题定位到sqlalchemy.exc

class StatementError(SQLAlchemyError):
    ...
    def __unicode__(self):
        return self.__str__()

并通过以下方式重现问题:

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

返回:

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)

我目前通过用从utf-8 解码的类替换相关异常来解决它。然而,这是一个可怕的 hack,我正在寻找一个合适的解决方案:

  • 有没有办法将 SQLAlchemy 配置为自动解码收到的错误消息?
  • 有没有办法配置 Postgres 以 latin 编码输出消息(不太受欢迎,但可以接受)
  • 有没有办法让unicode 尝试通过utf-8 而不是ascii/latin 解码?
  • 有什么办法可以解决吗???

(该问题仅与 Python2 有关。在 Python3 中,上面的代码有效。我相信这是因为默认编码是 utf-8

【问题讨论】:

  • 我认为这是 SQLAlchemy tbh 中的一个错误,__str__ 应该返回一个 str__unicode__ 应该返回一个 unicode。您应该将此作为问题提交。您可以通过在任何地方使用 print(str(e).decode("utf-8")) 来解决它,这很乏味,但不是世界上最糟糕的事情。
  • 我会将此作为问题提交。但我无法按照建议修复它,因为相关代码在 Flask-Admin 中。我需要一个更全球化的解决方案。
  • @tmrlvi 您能否在此处发布您提交的问题的链接?

标签: postgresql unicode sqlalchemy python-2.x


【解决方案1】:

我实际上认为从您的应用程序中修补 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)

【讨论】:

    猜你喜欢
    • 2010-11-01
    • 2012-10-15
    • 1970-01-01
    • 2011-04-15
    • 2021-03-27
    • 1970-01-01
    • 2022-12-06
    • 1970-01-01
    • 2011-05-13
    相关资源
    最近更新 更多