GAE开发问题总结及心得一览

开发 开发工具
本文总结了一些GAE的开发问题以及开发心得。本文写在Google的Java更新发布之后,文中所用的范例和代码皆为Python。

从接触GAE(Google App Engine)就可以想着在上面开发一个自己的程序进行试验,恰好有两个想法,一个是做一个公司部门使用的工作日志系统,可以由领导阅览每个人的工作日志;一个是想做一个个人记账网站,这主要是从我自己的需求出发的,父母老教育自己要有理财的意识,可惜就是没有这个意识,自己到底有多少钱花了多少钱都从来没有想过去整理和记录。时间有限,就选择了自己比较接近的记账网。

由于平时工作都只是做一些后台的设计工作,并没有太多做web的实际经验,制作过程中还是经历了很多痛苦的阶段,不过总算在摸索中磕磕绊绊完成了,下面就把制作过程遇见的问题进行一下汇总,和大家分享,希望大家遇见类似问题时有所帮助。

界面

Web程序最重要的是界面设计了,要有专门的美工才算专业。自己的小程序就没有想要那么专业的美工了,看着不太难看就行了。制作中还是长进了不少,重新学习了CSS。因为这个小程序内容不会占太长的篇幅,就把整体的框架设计成有阴影的box,上面是标题,左边命令栏,右边内容的框架。然后按照自己的想法,在Photoshop里画了出来,又请教了做美工的一个朋友,大体学了一下切图,就基于table+css把界面画出来了。把能做成重复的图片用css设置背景,减少下载图片的网络流量。

框架的选择

GAE本身提供web框架,但考虑到对django比较熟悉打算使用django,但经过测试怎么也不成功,就放弃了。对GAE提供的Web框架进行了学习,感觉和django的很类似,没有什么门槛。不过YAML的设置还是要注意的,特别是static,找了半天才搞明白。

数据库使用的问题

GAE提供BigTable的数据库,面向对象的数据库,不用再考虑ORM的问题了,使用起来还是蛮方便的。但使用过程中还是出现了一些误解,值得总结一下。

1:多个对象的References。如果一个Model的属性中要存放多个对象References怎么实现呢?如一个“支出项”有多个Tag。其实这可以看做是References的List。如下:

class VTag(db.Model):    user = db.ReferenceProperty(VUser,required=True)    name = db.StringProperty(required=True)class VInOut(db.Model):    user = db.ReferenceProperty(VUser)    tags = db.ListProperty(db.Key, "Tags")这样当然就没有自动调入的功能了,如果要访问,可以通过下面的方法:

sql = db.GqlQuery("SELECT * FROM VInOut")inouts = sql.fetch(1000)for inout in inouts:    rawtags = db.get(inout.tags)   rawtags就是由inout.tags为Key的VTag的一个对象列表了。

2:日期型属性的Bug。使用过程中发现了一个问题,就是如果Model的属性是日期型Date,则在查询或过滤条件中出现Bug,解决的方法是将Date型改为Datetime型。具体的可参加《 GAE Gqlquery Date属性不能设置为过滤条件的Bug》。

3:中文的问题。缺省情况下,数据库编码是ASCII编码,存入中文(UTF8编码)时会出现Bug,尤其是对于不太注意编码的朋友,可以参考《 Python中使用中文》。在编写程序时最好将所有的文件(程序文件、静态HTML模板等)都用统一编码方式,推荐用UTF-8。

还有,当从HTML的Form中接收到字符串数据的时候,一定要将送来的数据显式编码为UTF-8,如self.request.get('memo').encode('utf-8'),否则也会出问题。

另外,为了解决中文写入数据库时出错的问题,可以在写入数据库前做如下操作:

  1. import sys    reload(sys)    sys.setdefaultencoding('utf8'

或者

  1. code = sys.getdefaultencoding()   
  2. if code != 'utf8':   
  3.     reload(sys)   
  4.     sys.setdefaultencoding('utf8')  

其他的方法都试了,不太好使,只有这个非常管用!还有个奇怪的事情,GAE的开发环境不支持重复reload,会不能渲染网页,也就是说第一种方法会不能正常工作。所以最好用第二种方法,这样的话第一次刷新会出问题,后面刷新就不会有问题了。GAE的运行环境这两种是相同的,但是较长时间没有登陆网站的话偶尔还是会出现刷新白屏的Bug,这确实是由于重新载入sys造成的,所以首页最好不要reload sys,需要存入数据库的时候才重新载入sys并设置UTF-8为缺省编码。

4:Index.yaml的问题。index.yaml会由系统自动生成和更新,但是如果是没有这个文件就把系统直接上传到GAE,GAE会花十几个小时才能完全更新。在这段时间如果用到了,会出现need index的错误提示。解决的方法是,在本地完全测试,把生成的index.yaml直接上传,就不会出现上面的问题了。

5:密码md5保存问题。密码保存采用了md5哈希算法,按道理md5出来后是string,可以用StringProperty保存,但发现存是可以存,取出来再和正确的重新md5计算结果比较,会不同。解决的方法就是不用StringProperty而用BlobProperty,取出来后强制str就可以了。

6:TextArea多行出错的问题。这个问题是不小心造成的。当用StringProperty属性存储HTML的文本区(TextArea)内的字符串时,如果在TextArea中回车换行,存入数据库时会出现BadValueError: Property memo is not multi-line的错误。解决很简单,用TextProperty代替StringProperty,同时还要注意存入时也要明确编码为UTF-8,否则会报错,如:

  1. outthing.memo = db.Text(memo, 'utf-8'

session的问题

Web程序很大一部分会用到Sessions的,原先使用PHP、django时根本不用考虑Sessions是如何实现的,只要用就可以了。到了GAE,竟然没有内置的Sessions支持。好不容易找到了utilities,做了简单的测试可以使用就没管其他的了。可是真正使用的时候发现,Sessions中竟然只能存放string对象。不至于把所有的对象都变为string,取回来再变成其他对象吧。呵呵,都在进步,最新的utilities已经支持存放其他类型的对象了。有兴趣的可以看看它的代码,用的pickle。

最新的utilities Sessions(V0.5.1)实现中还是有一定的Bug。实现中使用了GAE的memcache,Session类有个memcache成员用于存储缓存的对象,但是由于会不定期的清除,造成访问某些对象时出错,主要的是__getitem__函数,我写到下面大家可以看看区别。

原始的:

  1. def __getitem__(self, k):   
  2.         """    
  3.         __getitem__ is necessary for this object to emulate a container.   
  4.         """   
  5.         if k in self.cache:   
  6.             return pickle.loads(str(self.cache[k]))   
  7.         if k in self.memcache:   
  8.             return self.memcache[k]   
  9.         data = self.get(k)   
  10.         ......   
  11.  

我修改后:

  1. def __getitem__(self, k):   
  2.         """    
  3.         __getitem__ is necessary for this object to emulate a container.   
  4.         """   
  5.         if k in self.cache:   
  6.             return pickle.loads(str(self.cache[k]))   
  7.         #修改开始   
  8.         if self.memcache != None:   
  9.             if k in self.memcache:   
  10.                 return self.memcache[k]   
  11.         else:   
  12.             self.memcache = memcache.get("sid-"+self.sid)   
  13.             if self.memcache == None:   
  14.                 memcache.set("sid-"+self.sid, {'sid'self.sid}, self.session_expires)   
  15.                 self.memcache = memcache.get("sid-"+self.sid)   
  16.         #修改结束   
  17.  
  18.         data = self.get(k)   
  19.         ......   
  20.  

就是做了self.memcache是否存在的判断,不存在重新添加。对于GAE的memcache的使用可以参考:《The Memcache API》。

发送email的问题

无异常发送不成功的问题。无明显异常但是发送不成功最有可能是因为mail.send_mail函数的sender不是本应用注册的那个EMAIL造成的,比如你用abc@gmail.com注册的52jizhang.appspot.com,那么sender一定要用abc@gmail.com否则会不成功的。

发送内容中有中文的不能发送问题。即使经过了前面数据库中中文问题的处理,发送EMAIL的中文依旧有问题,解决的方法是将发送的内容用str()包起来,:-)如下例:

  1. body = str("""亲爱的%s:   
  2.  
  3.             您的密码重设要求已经得到验证。请点击以下链接输入您新的密码:   
  4.  
  5.             http://52jizhang.appspot.com/regetpassword?confirmation=%s   
  6.  
  7.             如果您的email程序不支持链接点击,请将上面的地址拷贝至您的浏览器(例如IE)的地址栏进入我爱记账网。   
  8.  
  9.             感谢对我爱记账网的支持。   
  10.             我爱记账网 http://52jizhang.appspot.com/   
  11.             """ % (userid, confirmation_url))   

总结

上面对在开发我爱记账网中遇见的问题进行了一下小结,总体感觉GAE还是不错的,但也出现了较多的小问题,希望对大家在使用GAE中有所帮助,让我们一起进步吧o(∩_∩)o...。

【编辑推荐】

  1. Google App Engine:Java SDK 1.2.1发布
  2. Google App Engine对Java支持情况一览
  3. Google App Engine:坚定的站在Java的中心
  4. 开始您的第一个Google App Engine应用
  5. 教你如何在Google App Engine上运行PHP
责任编辑:yangsai 来源: CSDN博客
相关推荐

2009-07-28 12:52:50

ASP.NET coo

2009-12-08 13:54:31

PHP时间戳函数

2009-12-08 17:01:01

PHP PEAR DB

2022-04-02 20:27:30

ETS操作系统鸿蒙

2017-03-06 16:34:12

虚拟个人助理

2010-10-14 16:55:00

MySQL联结查询

2009-03-03 20:44:06

桌面虚拟化Xendesktop虚拟化

2020-02-17 15:29:00

石墨文档

2011-01-11 09:53:28

linux进程

2011-01-11 10:06:14

linux进程

2021-06-08 09:47:44

Java面向对象

2019-04-26 14:21:34

手机色彩苹果

2010-11-15 09:55:35

Oracle转换函数

2023-11-08 07:45:47

Spring微服务

2012-01-13 13:51:08

2010-04-08 15:14:59

Visual StudASP.NET 4.

2009-04-03 11:13:04

EclipseForce.comIDE

2009-08-07 14:55:15

ASP.NET复合控件

2009-07-23 13:10:00

Windows Emb

2009-07-06 15:23:18

JSP换行
点赞
收藏

51CTO技术栈公众号