Oh Bug!

Fun with Programming.

Google App Engine 入门(1) 简介

Google App Engine 是 Google 公司在2008年4月7日推出的一个开发、托管网络应用程序的云计算平台。它可以让你的网络应用程序在 Google 的基础架构上运行。

与 Google App Engine 类似的云计算平台还有 Amazon Web Service 和微软的 Azure 。Google App Engine 与他们不同的是 Google App Engine 给用户提供了一定的资源配额免费使用,当应用在免费配额无法负载的时候用户可以支付额外的费用以获得更多的CPU负载、带宽或是存储空间,用户只需要为使用超过免费配额的资源付费。

Google App Engine 最初只支持Python构建应用程序,2009年4月9日它开始支持 Java 构建应用程序。2010年5月20日 Google 发布 App Engine for Business,开始提供商用企业级云服务。

单个应用只能在Java 环境和 Python 环境之一中运行,App Engine 包括以下功能:

  • 动态网络服务,提供对常用网络技术的完全支持
  • 持久存储空间,支持查询、分类和事务
  • 自动扩展和负载平衡
  • 用于对用户进行身份验证和使用 Google 帐户发送电子邮件的 API
  • 一种功能完整的本地开发环境(SDK),可以在您的计算机上模拟 Google App Engine
  • 用于在指定时间和定期触发事件的计划任务
  • 高性能的内存键值缓存Memcache
  • 网址抓取,图像操作和任务队列

开通 Google App Engine 帐户
使用你的 Google 帐户登录 Google App Engine ,会提示你需要使用短信验证。

输入手机号码(带国家码如+8613612345678),提交后会收到一条短消息(Google App Engine Code: 4444243)输入数字验证码提交便通过验证了。

现在可以开始创建你的第一个 Google App Engine 应用程序。(输入你的 Google Voice 号码也是可以收到短信息的,本文即是使用我的 Google Voice 号码接收短信来验证的帐号。)

目前 Google App Engine(GAE)开发,Python 运行时环境是使用 Python 2.52版,Framework 使用 Django 0.96.1 版。

GAE相关教程
Python 文档
Java 文档
配额说明
启用付费
绑定域名

GAE相关资料
下载 Google App Engine SDK
App Engine 系统状态
App Engine SDK问题跟踪器
App Engine for Business

GAE 新闻
Google App Engine news and articles
Google App Engine Blog
-EOF-

GAE 查询1000条以外的记录

fetch()方法一次只能获取或者偏移1000条记录,这样对于两千条以外的记录就无能为力了。要么利用数据明确的标识来解决,如时间日期、ID等;好在GAE开发团队又提供了cursor()和with_cursor()来获取和设置游标,下面是例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
offset = 1234
last_cursor = None
while offset >1000:
  q = Blobs.all()
  q.order('-created_at')
  q.filter('deleted =',False)
  q.fetch(1000)
  last_cursor = q.cursor()
  offset -= 1000
 
q = Blobs.all()    
q.order('-created_at')
q.filter('deleted =',False)
if last_cursor:
  q.with_cursor(last_cursor)    
results = q.fetch(page_size, offset=offset)

-EOF-

A/B 向上取整


要写一个分页函数,需要获得两个数的商的向上取整,而Python里没有整除和浮点数除法的分别,虽然说乘个1.0就然后直接比较整除和浮点数除法的结果可以解决这个问题,或者我直接调用math.ceil(x)来解决这个问题,可我又不想导入一个module。于是找到了下面的这个公式,可以取得两个数的商的向上取整:

UP(A/B) = int((A+B-1)/B)

原文说A和B都需要大于1,其实不需要的,用带值法可以证明其实等于1就可以了。对于分页来说,这个公式完全满足条件,爽歪歪~
-EOF-

在Win32上为Python2.5安装SSL1.15

SSL for Python这个模块不像其它的模块直接下载下来执行setup.py install就安装好了,它需要编译再安装,过程遇到一些问题,这里记录一下如何安装成功的。
安装编译器MinGW
可以到MinGW网站下载GCC的win32版本 http://www.mingw.org/
如果已经安装了VC6或者VS2003等编译器,可以略过此步骤。
获取依赖文件

OpenSSL默认会安装在C:\Utils\GnuWin32,将libgw32c解压后也放在这个目录里。

获得ssl 1.15 Package代码
http://pypi.python.org/pypi/ssl/

修改setup.py文件
如果OpenSSL安装路径不是默认的,就需要修改如下内容

if sys.platform == 'win32':
 
    # Assume the openssl libraries from GnuWin32 are installed in the
    # following location:
    gnuwin32_dir = os.environ.get("GNUWIN32_DIR", r"C:\Utils\GnuWin32")

将C:\Utils\GnuWin32替换成实际的安装路径
修改cygwinccompiler.py文件
如果编译器版本不一致,还需要修改distutils\cygwinccompiler.py以跳过编译器版本检查,打开cygwinccompiler.py文件找到其中的如下内容(有两处):

result = re.search('(\d+\.\d+(\.\d+)*)',out_string)

修改成

result = re.search('(\d+\.\d+(\.\d+)?)',out_string)

开始编译吧
切换到ssl 1.15 Package解压目录下
编译并安装,运行命令

python setup.py build -c mingw32 install 
制作安装包,运行命令
python setup.py build -c mingw32 bdist_wininst

最后附上我打包好的安装文件,下载后直接安装即可。
下载 SSL1.15 for Python 2.52 (96)
参考 Compile ssl 1.15 for Python 2.5 or lower
-EOF-

GAE图像API使用


GAE中提供了Image服务用于简单的处理图片,下面这个类调用相关的API将数据库中的图片文件转换到指定大小(正方形),同时给图片加水印,处理完成后输出图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class PhotoviewHandler(webapp.RequestHandler):
  def get(self,img_id):
    p = db.get(img_id)
    if p: 
      MIN_SIZE = 500
      image = images.Image(p.blob)
      width = image.width
      height = image.height
      if width>height:
        rate = width*1.0/height
      else:
        rate = height*1.0/width
      size = int(MIN_SIZE*rate+1)
 
      new_image = images.resize(p.blob, width=size, height=size, output_encoding=images.PNG)        
      image = images.Image(new_image)
      right_x = round(MIN_SIZE*1.0/image.width,5)
      if right_x>1:
        right_x = 1.0
      else:
        left_x = (1- right_x)/2
        right_x = right_x + left_x
      bottom_y = round(MIN_SIZE*1.0/image.height,5)
      if bottom_y >1:
        bottom_y = 1.0
      else:
        top_y = (1-bottom_y)/2
        bottom_y = bottom_y + top_y
      new_image = images.crop(new_image, left_x, top_y, right_x, bottom_y, output_encoding=images.PNG)
      result = urlfetch.fetch('http://images.google.com.hk/intl/zh-CN_cn/images/logos/images_logo.gif')
      image = images.Image(new_image)
      new_image = images.composite([(new_image, 0 ,0, 1.0, images.TOP_LEFT),
                                    (result.content, 0 ,0, 0.8, images.BOTTOM_LEFT)],
                                   image.width,image.height,0, images.PNG)
      self.response.headers['Content-Type'] = 'image/png'
      self.response.out.write(new_image)
    else: 
      self.error(404)

-EOF-

Python 风格指南

一个典型模块的内部结构:

  1. 起始行
  2. 模块文档(文档字符串)
  3. 模块导入
  4. (全局)变量定义
  5. 类定义(若有)
  6. 函数定义(若有)
  7. 主程序

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env python
#coding:utf-8
 
"this is a test module"
 
import sys
import os
 
debug = True
 
class FooClass(object):
    "Foo class"
    pass
 
def test():
    "test function"
    foo = FooClass()
    if debug:
        print 'ram test()'
 
if __name__ == '__main__':
    test()

-EOF-

你好,世界!

#!/usr/bin/env python
#coding:utf-8
 
def helloworld():
    "Hello World! \
    \nWelcome to my blog."
    print 'Nice to meet you!'
if __name__ == '__main__':
    helloworld()

-EOF-