MySql+SQLAlchemy+wxPython的Unicode解决方案
2008-11-10 13:23:58 来源:WEB开发网我自己做的C/S架构的PIM是给予wxPython技术的,持久层用了MySQL5.0+MySQLdb+SQLAlchemy, 对于数据库的操作,单表的CRUD都是使用SQLAlchemy的Table来进行操作:
def insert(self, row_dict, table_name):
'''Insert row to table with all necessary data
'''
conn = ConnManager().get_conn()
trans = create_session().create_transaction()
try:
trans.add(conn)
tables = Table(table_name, ConnManager().get_meta(), autoload=True)
stmt = tables.insert()
rs = stmt.execute(row_dict)
trans.commit()
except Exception, ex:
trans.rollback()
loghelper.error(ex)
raise SQLError(ex)
而对于多表的CD,则是分解成单表的CD来进行处理,对于U,则是根据具体更新的数据来拼接SQL进行UPDATE的操作,对于查询,尤其是对于报表或者比较复杂的逻辑,都是根据拼接SQL来进行的。这样,使用的就是SQLAlchemy的text来进行操作。
def _do_query_result(self, sql_stmt, init_datas):
'''Execute query according to statema
'''
try:
stat = ConnManager().get_engine().text(sql_stmt)
return stat.execute(init_datas)
except Exception, ex:
raise SQLError(ex)
整个PIM系统的初始化方法中,已经将系统的encode设置成为utf-8,代码如下:
reload(sys)
sys.setdefaultencoding('utf-8')
这样,wxPython的每个widget的GetValue方法,返回的值也是utf-8编码的了。
在MySQL那里,pim使用的数据库,以及其中的表的定义中使用的charset也是utf-8。使用SQLAlchemy中table的CU方法的时候,基本上没有什么问题。如果是没有过滤条件的单/多表findall方法,因为在封装SQLAlchemy的方法中,将获取的字段做了decode的操作,所以,也可以保证返回到wxPython那里的数据也是utf-8编码的。剩下的问题就是,当调用SQLAlchemy的text方法传入的参数有非拉丁文字的时候,会报如下的错误:
(UnicodeEncodeError) 'latin-1' codec can't encode character u'u4fa7' in position 0: ordinal not in range(256) 'select * from task_type where ( tasktype >= %s) order by tasktype' [u'u4fa7']
原本不希望修改SQLAlchemy和MySQLdb的文件,通过调用它们的api来解决,但是,始终没有办法。后来,我将SQLAlchemy封装调用MySQLdb部分的代码中异常处理的部分去掉,从而跟踪到确实是MySQLdb的connections.py的255行中的set_character_set方法,无论调用了'set names utf8'等等方法,获得的charset始终是latin-1。晕了,我也没有耐心去仔细琢磨到底是怎么回事情了,就把charset设置为utf-8,于是,查询就Ok了。
测试CRUD操作的时候,中文、英文和韩文一起显示和混合录入都没有问题,至此,应该可以说PIM的Unicode问题已经基本解决。