2007年11月2日

升级Django到svn trunk需要做的工作

作者 非鱼

花了不少时间,走了不少弯路,多了不少Bug,总算是把理财易的Django升级到svn trunk版本了,值不值得还不知道,不过,用新的总归没什么坏处,而且,1.0已经不远了,现在做好准备也不错。

首先删除原来的Django 0.96版的安装,全新安装svn trunk版,启动服务器,打开首页,出现一堆错误。首先是前面提到过的那个用来做“记住密码”密码功能的自定义的DualSessionMiddleware,它引用的页面发生了变化,SessionWrapper类已经不存在了,所以启动报错。暂时修改Settings文件,使用默认的session middleware,OK,通过了。然后提示_()函数不存在。这个是gettext函数,用来做多语言界面的,查了一下 兼容列表,果然,这个函数被移除了。于是在所有出现这个函数的文件里加上from django.utils.translation import ugettext as _,通过。进留言板,进不去,提示编码转换错误,什么"ascii can not decode”什么的,跑到官网一查,说是什么修改了对Unicode字符串的处理,现在整个系统各个环节的Unicode已经统一(大概是输入,转换,和输出)。结果是:需要把所有的用%来拼接字符串的地方,加上u标志。比如s=’用户名%s不存在’ % username,如果这个username是中文,这里就会报错,一定要把前面的这个变量加上u,标明这是Unicode变量。

改了N多地方,总算又通过了,然后继续测试,发现另一个地方又是转换错误,但是这里只是把一个包含中文的数组用join的方法串起来,我去哪里加这个u呢?想来想去,找到了定义这些中文的地方,在每一个中文变量的前面加上u,通过了。现在,代码变得相当丑陋了。(为了给省和市的名字加这个u,做了近200个替换,也不知道有没有留下后遗症)。

想到的地方都解决了,就更新到了服务器上。结果第二天有人报告无法注册,原来检查用户名是否符合规则的地方也变了。以前获取到的用户输入都是UTF8的,用正则来判断是否包含中文,需要先转换成Unicode,于是对输入字符串做了一个decode(‘utf8’),现在,这一步变成了多余的,所有的输入本来就是Unicode的。(但是读写数据库的时候似乎会自动转换成UTF8,否则写入Mysql应该会报错。)

后来又想到WAP那边也有中文的处理,打开手机一试,果然如此,中文用户无法登录了。以前的解决方案是利用客户端的能力,把输入的字符串编码成URL模式,中文会变成%D7%B7这样的字符串,拿到以后用urllib.unquote来解析出来,然后,如果客户端是UTF8的,要用decode(‘utf8’)来处理,如果客户端是gb2312的,要用decode(‘gb2312’)来处理。(虽然我在所有的WAP页面里都指定了编码是UTF8,但是在我的Palm上使用Blazer浏览器,仍然是GB2312编码的。)因为无法预知客户端如何编码,所以用try做两次解码。但是现在,不管用哪个,都会报错。

在这个问题花了许多时间,尝试各种各样的解码规则,都失败了。后来终于想到了问题所在,在不使用任何解码的情况下,服务器端接收到的是%D7%B7的字符串,说明这一步是正确的,然后,在unquote以后,文字就已经变成乱码了,按理说,应该只是把%变成\x而已。这一步实在是出乎意料,因为按理说收到的都是英文字符串,难道对英文字符串的处理也会因为编码而不同?经过测试,还真是如此。以前request.get拿到的字符串是没有编码的,也就是说%D7%B7就是作为一个普通的ascii字符串,但是现在,这个字符串被作为了Unicode字符串。unquote方法在解析Unicode字符串的时候,得到的结果是错误的。知道了问题,答案就找到了。先对输入的字符串做一个encode(‘ascii’),再进行unquote,啊,终于结束了。

另外,系统在从0.96更新到0.96.1的时候(也就是打了那个多语言方面的补丁以后),多语言功能消失了。IE的用户看上去是正常的,但是Firefox的用户看到的都是英文。(如果Firefox的语言选项里只有zh和zh-cn,那他看到的是中文,如果有了en,哪怕是在最下面,还是会显示英文界面。)跑到google group里去发了个帖子,最后得到了官方的回复,这是他们的一个Bug,在修改的过程中出错了,而且,只有zh-cn,zh-tw和pt-br出错,zh-cn需要改成zh_CN,在conf下面的default setting文件里。算了,还是不要改了,反正暂时关了多语言也没关系,等官方版本修改了这个再说吧。

11月4号更新:今天根据用户的反馈,测试了一下,发现Opera访问WAP的问题还是没有解决,中文编码不正确。不只是WAP上,用PC上的Opera登录WAP站,它的中文也有问题。在Postfield里面使用:e标识符以后,其它的浏览器都会根据自己的编码(gb2312或utf8)对中文进行URL编码然后发送,但是在Opera上编码以后,却丢了一半的值(一个汉字经过GB2312的URL编码以后应该是%D7%C7这样的两组值,但是Opera却只返回了后面的这一个,解码当然就不对了。

改了几种编码都不对,后来把:e的编码方式去掉一试,居然成功了。看来Opera对中文的兼容性已经远远超越了其它的手机浏览器,能够不编码发送完整的中文到服务器端。但是把:e去掉以后,别的浏览器又不对了(Palm上的Blazer会丢掉最后一个汉字)。不过既然知道了具体的现象,也就有解决办法了。通过服务器端判断User_Agent是否包含Opera字符来判断用户使用的是不是Opera浏览器,如果是,在生成页面的时候就不要添加:e标识符。经过测试,PC上和Palm上的Opera Mini都已经可以正常使用中文了。