2017-04-23 61 views
7

我正在使用postgres/SQLAlchemy/Flask-Admin處理Flask應用程序。但是,在Admin界面中,由於unicode(exc)會產生UnicodeDecodeError,因此無法報告包含Unicode字母的任何數據庫錯誤。SQLAlchemy在異常中的Unicode問題

我能夠一起找到問題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) 

我目前解決這個問題用我的從解碼的類取代相關的例外。但是,這是一個可怕的黑客,我正在尋找一個適當的解決方案:

  • 有沒有辦法配置SQLAlchemy自動解碼接收到的錯誤消息?
  • 有沒有辦法在latin編碼(不太有利,但accetable)
  • 有沒有辦法讓unicode嘗試utf-8,而不是ascii/latin解碼配置Postgres的輸出信息?
  • 有什麼辦法可以解決它?

(問題是相關的只有Python2在Python3上述工程的代碼。我相信這是因爲默認的編碼是utf-8

+0

我所說的,在SQLAlchemy的TBH一個bug,'__str__'應該返回一個'str'和'__unicode__'應該返回一個'unicode'。您應該將此作爲問題提交。你可以通過在所有地方執行print(str(e).decode(「utf-8」))來解決它,這很乏味,但不是世界上最糟糕的事情。 – univerio

+0

我會將此作爲一個問題。但是我無法按照建議修復它,因爲相關代碼位於Flask-Admin中。我需要一個更全球化的解決方案。 – tmrlvi

+0

@tmrlvi您可以在這裏發帖鏈接到您提交的問題嗎? –

回答

2

其實,我覺得從您的應用程序打補丁的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)