Google App Engine SDK Version 1.2.6更新

收取Email - 你的App Engine程序以前就可以发送Email了...但是现在,随着1.2.6版本的到来,你的程序可以实现接收email功能了。在起用mail作为Inbound服务(就像XMPP)以后,用户可以使用类似whatever@yourappid.appspotmail.com这样的地址给你的程序发送mail。Inbound信息被转变成一个你可以接收的webhook句柄HTTP请求(同样类似XMPP)。关于这部分的文档,Python版和Java版。

删除一个程序 - 我们的开发人员收到了很多希望实现删除不再使用的程序功能的请求(Top5的特性请求之一)。这一特性已经可以在管理后台实现!可以通过访问Application Settings页面获得更多信息,更多

数据库状态 - 你现在可以在管理后台看到程序数据的更多统计细节。这些信息也可以通过程序来访问,文档Python, Java

更多细节察看Release Notes

Google App Engine SDK Version 1.2.5更新

  • Python和Java的SDK版本更新到了1.2.5- 下载
  • App Engine现在可以通过XMPP协议来收发消息,支持和类似Jabber或者Google Talk这样的即时通讯服务进行通信。
  • Java SDK现在有测试Task Queue服务的API
  • Java SDK现在支持所有的内置数据类型,包括GData类型,比如GeoPt
  • JDO和JPA现在支持使用查询来删除实体
  • JDO现在可以使用makePersisitentAll()和deletePersistentAll()进行数据批处理操作
  • 数据实体的key现在可以使用数字开头,不再需要用户ID必须使用非数字字符来作为实体key的前缀
  • 数据transactions现在支持多次同步写入和删除实体在一个transaction过程中
  • URL Fetch请求现在能够设置Referer的Header。如果程序不设置header,将不对headers请求。此前,App Engine一直强制使用特定的App Engine header
  • Java程序现在可以使用java.net.URLConnection接口的setConnectionTimeout()为URL Fetch设置deadline
  • Java程序可以在开发环境的web.xml中使用元素调整MIME类型
  • Java程序可以使用appengine-web.xml文件控制浏览器缓存过期的时间
  • bulkloader加入了一个试验中的特性,可以删除和恢复每个实体而不需要加入任何代码和设置。目前这个特性仅仅在bulkloader.py工具中可用;这一功能将在稳定后被移动到appcfg.py工具中
  • Python SDK for Windows现在加入了图形化的接口来提供创建、测试和开发项目的功能。这一功能和Mac上的Launcher一样。Windows版本的启动器使用Python和wxWidgets开发,所以Linux用户也可以下载
  • 使用Python appcfg.py request_logs命令行,你现在可以调整log的日期来使用--end_date参数下载代码。而且文档已经加入了介绍以前版本的--include_vhost参数

Google App Engine SDK Version 1.2.4更新

[via]

GAE技术文章更新和一些新的开源项目

App Engine团队近日更新了App Engine文档中一些介绍程序扩展性的文章——编写可扩展性程序的最佳实践。此外,新的文档的分类也更加详细。

GeoModel开源项目

GeoModel是用来索引和查询的地理空间数据的一个开源项目,由Google Earth API的工程师Roman Nurrik发起。GeoModel使用称之为geocellsgeohash-like对象来进行索引和查询。GeoModel不仅优化了基本房地产搜索/商业定位,而且可以适用于大型的数据集。

使用GeoModel开发者可以通过继承GeoModel中的类迅速建立地理背景的数据模型。目前,数据实体可以与一个单一的地理坐标对应,随后索引和过滤符合周围地区或接近(最近n )到搜索中心点的坐标。

其他开源项目
  • GaeVFS,使用App Engine数据存储移植的Apache Commons VFS插件,使用了数据库和memcache APIs。
  • GraniteDS 2.0,支持App Engine for Java:Granite DS是一个为Java EE服务器开发的Adobe生命周期数据服务的替代品,支持服务器的推进和持续机制。更多信息请参考他们的announcement
  • jiql是基于JDBC的包装的应用程序引擎的低级别的数据存储的API,提供了开发人员熟悉的分布式数据库的接口。
  • pQg是基于PHP的从SQL到JDO的概念程序和一些范例

Google App Engine SDK Version 1.2.3更新

关于GAE你可能不知道的十件事

  • 程序版本号并不是number类型而是string
    尽管在多数的例子中都将app.yaml和appengine-web.xml中的'version'字段作为number类型,实际上这只是人们的一种习惯。程序版本可以是任何URL中允许的string类型。例如,你可以将你的版本设置成"live"和"dev",这样你就可以通过"live.latest.yourapp.appspot.com"和"dev.latest.yourapp.appspot.com"这样的地址来访问了。
  • 你可以在程序中同时使用多个版本
    这里有一点是很NB的,不同的版本可以使用不同的运行环境。换言之,你可以为你的程序开发使用Java语言的版本和Python语言的版本。
  • Java运行时支持任何编译成Java bytecode的语言
    这就是为什么人们需要Java runtime的原因,一旦这家伙被支持了就等于你可以在GAE上使用什么JRuby,Groovy,Scala,Rhino(JavaScript编译器),Quercus(PHP编译器),甚至Jython!
  • 使用'IN'和'!='运算符可以生成多重数据查询
    例如,查询"SELECT * FROM People WHERE name IN ('Bob', 'Jane')"将会被编译成两个查询等价于使用"SELECT * FROM People WHERE name = 'Bob'"和"SELECT * FROM People WHERE name = 'Jane'"并合并查询的结果。
    查询"SELECT * FROM People WHERE name IN ('Bob', 'Jane') AND age != 25"将会为每种可能生成生成查询,(age小于或者等于25, 和name是否为'Bob'或者'Jane'),然后将每种可能合并成结果。
  • 你可以使用批处理执行put,get和delete操作来提高效率。
    每当你做出一个数据请求,比如一个查询或者get()操作,你的程序将会对数据库发出请求,而数据库将会执行这些操作并返还一个response。请求到响应的循环过程将会花费一定时间,所以如果你执行的请求过多的话将会导致用户等待结果的时间过长(万恶的datastore timeout: operation took too long异常)。
    很幸运的是,GAE提供一个简单的方法来减少数据查询中的这种循环:批处理操作。db.put(),db.get(),和db.delete()函数都可以接受可选的list参数来执行操作。当一个传递一个list以后这些操作将会并行的遍历list的每一个元素,这样就大大节省了操作的时间。例如:
    for entity in MyModel.all().filter("color =",
        old_favorite).fetch(100):
      entity.color = new_favorite
      entity.put()
    
    更新操作需要一个数据库往返的查询,还需要加上一次操作来更新数据库中实体的属性————也就是说一共需要101次的往返!再看下面的例子:
    updated = []
    for entity in MyModel.all().filter("color =",
        old_favorite).fetch(100):
      entity.color = new_favorite
      updated.append(entity)
    db.put(updated)
    
    这个例子中只需要2次数据库往返,也就是说我们将101次往返减少到了2次。
  • 数据库的性能并不取决于其中实体的数量
  • 建立索引的时间开销并不全部取决于它的大小
  • 'Stored Data'的值是按日更新的
  • app.yaml,web.xml和appengine-web.xml中指明了项目的处理顺序
    人们经常犯的一个错误是忘记配置程序处理文件的顺序是自上而下的。比如,当使用remote_api时候很多人这样做:
    handlers:
    - url: /.*
      script: request.py
    
    - url: /remote_api
      script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py
      login: admin
    
    上面的例子看起来没有什么问题,但是由于handler是按照顺序处理的,request.py是首先出现的,而所有请求包括对remote_api的请求都是使用request.py处理的。由于request.py加载后并没有出现remote_api,所以就会造成a 404 Not Found error的错误。解决的方法是将request.py的handler放置到remote_api的handler下面。在Java环境的配置文件中也是一样。
  • 你不需要手动构造GQL字符
    下面是一个反例:
    q = db.GqlQuery("SELECT * FROM People "
        "WHERE first_name = '" + first_name 
        + "' AND last_name = '" + last_name + "'")
    
    很幸运,GAE支持在GqlQuery语句中使用参数替换,上面例子可以改写成:
    q = db.GqlQuery("SELECT * FROM People "
        "WHERE first_name = :1 "
        "AND last_name = :2", first_name, last_name)
    
    GqlQuery还支持使用name来代替数字参数:
    q = db.GqlQuery("SELECT * FROM People "
        "WHERE first_name = :first_name "
        "AND last_name = :last_name", 
        first_name=first_name, last_name=last_name)
    
    这样做出了能使代码看起来更加简洁以外,还可以进行一些优化。如果你需要使用不同的值来进行多次同样的查询,你可以使用bind()函数来为每个查询重新绑定参数。这比起每次都要构造新的查询更加快捷,因为查询只需要分析一次:
    q = db.GqlQuery("SELECT * FROM People "
        "WHERE first_name = :first_name "
        "AND last_name = :last_name")
    for first, last in people:
      q.bind(first, last)
      person = q.get()
      print person
    

作者Nick Johnson, App Engine Team[via]

Google App Engine SDK Version 1.2.2发布

  • 新的quota API将当前请求转向CPU使用
  • Urlfetch开始支持自定义deadlines
  • SDK中的Urlfetch允许设置在header中设置Encoding来匹配appengine
  • urllib现在增添了对https支持
  • 数据库的indexes现在可以通过设置在属性构造函数中设置indexed=False来禁用
  • 数据库api支持Key-only查询,或者使用SELECT __key__ or db.Query(Model, keys_only=True)
  • 修复IN关键字的筛选和排序问题
  • 修复开发服务器控制台(/_ah/admin/datastore)当某属性是NoneType时不能显示的问题
  • Bulk Loader改进:新的appcfg下载数据命令,更好的后台支持和debug长请求输出
  • appcfg中新增参数--vhost会为特定的host选择记录
  • 可以通过import导入Python的_ast模块
  • 修复Images API颜色参数问题

另外最近还加入了web2py的支持,不过依然是不支持管理后台数据库等等,总之和django一样反正是你什么用的顺手就不支持什么。

Google App Engine SDK Version 1.2.1更新

使用多选框和HttpRequest提交数据

我记得google.appengine.ext.db的djangoforms里面的确是有个类叫做ModelMultipleChoiceField,但是现在已经没有了,不过ModelChoiceField还在。我目前的问题是想建立由模型生成的表单,通过checkbox提交这个模型中被选择的数据,如果checked那么将所有数据提交到一个模型的ListPropery属性形成一个key的列表,否则的话就不提交。

if request.method == 'POST':
   choosed_players_key = []
   post_players = request.POST.getlist('player')
   choosed_players = models.Players.get(post_players)
   for player in choosed_players:
      choosed_players_key.append(player.key())
      players_list.players = choosed_players_key
   players_list.put()
players_list是一个包含ListProperty的模型的实例,它的这个属性是由db.Key构成的,但是当我直接让:
players_list.players = request.POST.getlist('player')

的时候却发生了错误,players_list.players这个db.Key竟然是Key.from_path()生成的列表,所以后来改成先通过request.POST.getlist('player')获得所有player对象,然后在通过对象获得对象的key,再把这些key形成列表,最后再把这个列表赋值给players_list的players属性,这样竟然就可以了。

参考:附录H HTTP请求(Request)和回应(Response)对象

Google发布Google App Engine SDK for Java

Google App Engine SDK for Java果然如约而至,看来在Issues list长期排名第一的feature Request果然起到了一些作用。GAE的Java运行环境为Java6JVM,支持JDO(Java Data Objects)、JPA(Java Persistence API),JavaMail,JCache。此外Google还提供Google Plugin for Eclipse使用Eclipse和Google Web Toolkit开发App Engine for Java项目。

Java运行环境

App Engine使用Java6的虚拟机。App Engine SDK支持Java5和更早的版本,Java6虚拟机能够运行任意版本Java编译出的程序。

App Engine使用Java Servlet作为Web应用程序。你可以在程序目录中提供你的servlet类,JaveServer Pages(JSPs),静态文件和数据文件,web.xml和其他配置文件。App Engine的服务器请求通过根据web.xml创建的servlets启动。

JVM使用'sandbox'的运行环境来独立你的程序。"sandbox"能够确保你的程序仅能够执行而不影响其他程序性能和扩展性。比如,一个程序不能超越线程,将文件写入本地系统或者建立网络连接。一个程序只能使用JNI或者其他的代码。JVM能够执行任何在"sandbox"允许运行的java代码。更多内容参考Servlet运行环境

数据库、服务和标准接口

App Engine提供可扩展的服务,程序可以存储数据、通过网络访问资源,和执行其他任务比如操作图片数据。程序访问Java的服务可以通过建立Java提供的各种APIs来进行。每个服务都可以通过提供一个完整的low-level接口来移植新或者直接访问。 App Engine Datastore访问用到的Java Data Objects (JDO) 2.3和Java Persistence API (JPA) 1.0似乎都使用DataNucleus Access Platform这个工具进行了移植。

对App Engine Memcache进行操作的工具是JCache (JSR 107).对于URL Fetch功能App Engine for Java采用java.net.URLConnection和java标准库中一些相关的类来实现。App Engine for Java使用JavaMail来发送email信息。图片服务使程序能够转换和操作图片数据,包括裁剪、转动、缩放和颜色变化。这一服务能够处理CPU-intensive Image处理任务,而节省服务器可用资源来处理web请求。程序可以使用Google Accounts来进行用户验证。Google Accouts处理用户帐户创建和登陆,已经注册的google用户可以使用帐户直接登录你的程序。Java程序可以使用在开发环境中使用安全限制来控制Google Account的访问,通过对servlet请对象使用getUserPrincipal()方法能够检测用户是否已经登陆。一个程序能够使用low-level Google Accounts API来生成登入和登出的URLs,并通过读取用户数据库中数据获得用户对象。

计划任务

程序能够通过设置一定的时间间隔来访问URLs的计划任务。更多内容查看Cron Jobs

为JIEblog生成符合规范的网站供稿

最近着手改进网站的代码,一方面通过memcache降低CPU使用,另一方面想把网站供稿在feedburner上烧制一下,以减少网络程序访问产生的CPU占用。以前的供稿在Google Reader上虽然显示正常,但在Feedburner上烧录后却只有乱码。研究了一下发现是由于feedburner是根据供稿的编码来识别代码,而不是根据实际的编码,因为这个XML模板是用Intype默认的ANIS编码编写的所以造成了这个错误。

另外用http://feedvalidator.org/验证了一下这个供稿,发现还有不少问题。文章内部字符和标记的错误就不计了,剩下的主要是时间格式不符合规范。其实以前这个时间规范的问题一直会影响Google Reader,不过不知道Google什么时候改正了时间显示的方式,用Google Reader抓取的时间代替了供稿生成的时间,所以我的这个问题也一直没有修正。

Atom使用的这个时间格式标准被称为rfc3339 Timestamps,其实编写一个能生成符合这个rfc3339标准的python代码也不算难,而我可能以后会用django生成的供稿,所以为了节约时间还是直接Google了一个rfc3339 for Python,上面还有Pyfeed这种东西,真是遗憾了,以后干什么一定要先Google一下。

在用http://jieblog.appspot.com烧录的时候发现feedburner居然直接识别了appspot的子域名并且返还了这么个地址http://feeds.feedburner.com/appspot/euFN。不过在没有修改完善之前还是不使用这个供稿了,毕竟修改供稿造成阅读器的项目混乱是很麻烦的。

为JIEblog添加Memcache

虽然从控制台上看Application Quotas还都够用,但是Current Load里首页和feeds两个项目平均CPU占用都有警告:

This URL uses a heigh amount of CPU and may soon exceed its quota.

看着总是不太舒服。首页的高CPU自然比较正常,而feeds因为我没有使用feedburner这类的工具烧制RSS现在的确有点后悔了,再加上这个feeds还是Google Webmaster工具的Sitemap所以占用也会很高。而Google Reader甚至有时候在我发布文章后1分钟内就会更新。

Appengine的FAQ里提到衡量CPU使用的两个主要途径是:

  1. Runtime CPU:应用程序本身产生的CPU使用,这显然是和代码的质量有关系
  2. API CPU:用于调用App Engine API产生的CPU使用,例如:datastore API , urlfetch API, image API, 等。

第一条我显然没有太多时间做。。。所以直接转向第二条,使用Memcache进行优化。Appengine文档里有个很简单的例子,目前我只用Memcache尝试提取首页的Post数据,然后看看效果是否明显:

def get_data(the_key, time_exp):
  data = memcache.get("Post")
  if data is not None:
	return data
  else:
	data = query_for_data()
	if not memcache.add(the_key, data, time_exp):
		logging.error("Memcache set failed.")
	return data

通过使用这个函数,首先检查memcache的data是否有the_key这个数据,如果有的话直接返还data,如果没有的话则调用query_for_data()这个函数。然后将query_for_data()的结果加入memcache,而memcahe则是按照设定的time_exp进行更新。

GAE数据备份及恢复程序Gaebar

Github的Blog Rebase 9在本周介绍了这个程序,作者又在圣诞节这一天制作了视频来演示Gaebar的使用方法。Gaebar是一个独立的基于Django的程序,可以作为插件集成在使用Google App Engine Django或者app-engine-patch开发的应用中来备份和恢复Appengine上存储的数据。

Gaebar可以将Appengine的数据备份到Python代码中,而且可以执行这些代码来进行数据恢复。作者在程序中使用了Ajax来调用备份程序以避免产生Appengine不支持的长时间数据操作。为了避免产生过高的Cpu负载Gaebar默认每次备份五行数据,产生的备份文件也被分割为约300KB以避免发生Appengine 1m文件的限制。

源代码地址:

使用Zoho Creator和App Engine Site Creator构建GAE程序

这是appengine官方blog上的一篇文章。

首先先是Zoho Creator的开发人员已经为Zoho Creator添加了生成GAE代码的功能。在用Zoho Creator创建了应用之后,在上面的More Actions的下拉菜单里有一个Deploy in Google Appengine的选项可以直接下载这个应用的python代码。目前Zoho Creator仍旧有一些在Appengine上不能实现的功能,包括:

  • 文件上传和Notes field
  • 使用Criteria的Views
  • 使用运算符的分组
  • HTML, Summary和Calendar视图
  • Zoho Creator的主题支持
  • 受限制的Deluge Scripting支持(仅支持邮件通告)

App Engine Site Creator,可以说这是一个简单的内容管理系统(CMS),类似Drupal这样的程序。目前感觉功能还不完善,毕竟开发才刚起步,GUI风格感觉很像Google Cookbook - Google App Engine。不过按照他们的说法这个程序还是很值得期待的:

The resulting managed site is designed to be themed and branded, and the back end Site Creator code was written with readability and extensibility in mind.

很期待GAE上能有类似Drupal和Movable Type这样的程序出现。

Google App Engine SDK 1.1.7更新

忽然发现自己xp上的appengine SDK才更新到1.1.5版本...

Google App Engine SDK 1.1.6添加了一些新特性、更新了数据库方法和fetch:

  • 现在可以使用entity的key来进行排序和筛选
  • 现在可以直接使用key来删除entity,而不需要事先获取Model
  • 当你在创建一个Model的时候指定key_name,这个key在使用put()方法之前就可用了
  • 现在可以直接使用key来删除entity,而不需要事先获取Model
  • URLFetch在SDK中会有一个5秒的timeout

修正了一些bug:

今日发布的Google App Engine SDK 1.1.7修正了1.1.6的Issue 877

App Engine项目app-engine-patch

app-engine-patch是一个类似appengine-helper的开源项目,主要作用还是在App Engine上更好的实现django的一些功能,与appengine-helper不同的是app-engine-patch支持的东西更多一些,按照他们的说法app-engine-patch最低限度支持django1.0。

主要特性:

  • 支持manage.py
  • 支持Django的authentication framework(不需要google帐户)
  • 支持Django的后台数据库和线程
  • 支持Memcache
  • 支持Django的电子邮件功能
  • 支持django.forms包中的大部分ModelForms
  • 支持Django的testing framework
  • 取代Python原有的httplib(支持boto)
  • 集成profiler
  • 支持通用视图

ragendja(代码库):

  • 增强管理框架:你可以使用你自己的用户类
  • LoginRequiredMiddlewar中间件能够使你不再需在视图前添加@login_required
  • 基于RequestContext的render_to_response()(这个好像本身app engine就支持)
  • 改进的模板载入功能去掉了文件名称空间的前缀
  • 全局的模板tag
  • @transaction decorator
  • JSONResponse
  • ModelTestCase可以改变DB内容
  • 更多

在JIEblog上实现XML-RPC

虽然写这篇文章的时候我的这个API还有好多问题,但我还是迫不及待的想把实现这个功能的过程记录一下。最初的动力就是想能够使用WLW(Windows Live Writer)来发布文章,实际上也就是实现一个简单的XML-RPC。所谓XML-RPC就是:remote procedure call,即远程程序调用。它采用HTTP 作为传输协议,并使用XML词汇表作为消息的载体。

这里要实现的是一个XML-RPC的服务端,Python中的SimpleXMLRPCServer,就是用来实现XML-RPC服务端的模块。首先要导入SimpleXMLRPCServer的SimpleXMLRPCDispatcher模块和django的HttpResponse:

from SimpleXMLRPCServer import SimpleXMLRPCDispatcher
from django.http import HttpResponse

然后使用POST方法写入:

response = HttpResponse()
if len(request.POST):
response.write(
dispatcher._marshaled_dispatch(request.raw_post_data)
)

最后通过把函数注册给dispather:

dispatcher.register_function(
server_function_name,'client_function_name'
)

WLW支持的API的确是非常全,包括很多知名和未知名的Blog API,比如BloggerWordpressdasBlogTypepadMovable Type等,最终还是选择了Metaweblog API…这个能参考的代码比较多。

Metaweblog API主要的三个函数是:

  • metaWeblog.newPost (blogid, username, password, struct, publish)用来发布新文章并返还字符串
  • metaWeblog.editPost (postid, username, password, struct, publish)用来编辑文章并返还一个布尔值
  • metaWeblog.getPost (postid, username, password) 用来获得一篇文章并返还struct

此外还需要使用Blogger API中的一些函数来完善:

  • blogger.getUsersBlogs(appkey,username, password)返还程序的根目录、ID和名字
  • blogger.deletePost(appkey,username, password)用来删除一篇文章

Metaweblog API中还定义了一些方法:

  • metaWeblog.newMediaObject(blogid, username, password, struct)返还struct
  • metaWeblog.getCategories (blogid, username, password)返还structs
  • metaWeblog.getRecentPosts (blogid, username, password, numberOfPosts)返还struct的数组

在看了这篇文章后发现原来blogger已经实现了新的Blogger Data API,以后可能会考虑在JIEblog上实现这个新的api,毕竟这种方法应该可以直接进行用户的验证。

谷歌发布中文开发者首页

谷歌黑板报上是这样写得:

欢迎你来访谷歌中国开发者博客网! 请尽情浏览我们的开发者首页,参阅大量的有关 APIs 和开发者产品的参考文件、录像、以及许多档案资料。我们还将有包含开源和托管项目的内容,这些内容丰富的参考资料和源代码的样本,将使您获得前无所有的编程效率和速度。

原来我订阅半年多的谷歌黑板报现在才正式发布?不过中文开发者首页的确是不错的东西,里面大量文档目录已经翻译成中文,看来中文化还有很长的道路要走...

另外Google App Engine SDK 1.13也已经可以下载了,更新:

GAE在线网址搜藏项目——meja

http://meja.blzinsider.cn
http://meja.appspot.com
启动一个在线网址搜藏项目,依然是GAE+django,因为这个应用可能用到javascript的地方比较多,所以决定加入yui。(meja是以前一位朋友所钟爱的瑞典女歌手的名字,碰巧在appspot还能用)

meja需要的一些功能:

  • 多用户支持
  • 从firefox收藏夹导入导出
  • 输出atom和json
  • ajax编辑界面
  • 简单后台

在GAE中实现的文件上传和下载

blzinsider uploader

作为一个djangoGAE的初学者,直接使用GAE支持的那部分django编写程序并不是一个很好的选择,而这个Blog就是用这种方法写的,不过既然开始就错了,还是让这个错误继续下去吧...

使用这种方法在很多情况下都可能遇到django手册中无法实现的东西,在编写这段程序的时候首先就发现djangoforms没法使用FileField(),不过手册里面也有其他的方法:

if request.method == 'POST':
for f,file_info in request.FILES.items():
file=models.FileUpload(filename=file_info['filename'],
content_type=file_info['content-type'],
content=db.Blob(file_info['content']),
owner=users.get_current_user(),
size=len(db.Blob(file_info['content'])))
file.put()
return HttpResponseRedirect('/uploader')

首先构建一个名为FileUpload并且包含上面属性的model,Blob用来存放二进制的文件。上面这段代码是的django的一个HttpRequest object,request.FILES是一个包括三个属性的字典类型:content,filename,content-type。这样文件就会存放在数据库的content属性里。

接下来是要在网页上输出这个文件,首先注意的是上传的文件并没有存放在网站上而是存放在FileUpload这个数据库的content里,所以输出这个文件只要通过每个字段的key就可以了。

the_file=models.FileUpload.get(the_key)
response=HttpResponse(the_file.content)
response['Content-Type']=the_file.content_type
return response

这段代码是生成一个django的HttpResponse objects,指定Content-Type是为了让程序能够识别文件类型,也可一写成:

response=HttpResponse(
the_file.content,mimetype=the_file.content_type)

或者直接指定文件的类型。如果加入Content-Disposition会使程序直接下载该文件:

response['Content-Disposition']=
'attachment;filename=%s'%the_file.filename

参考:

使用.CN域名注册Google Apps

出于某些原因Google Apps并不支持.cn的域名,而我又非常想把这个域名用在Gae上。按照plog的做法:使用一个非.CN域名注册Google Apps然后把你的.cn域名注册成该非.cn域名的别名,完成后回到Gae的Version设置上,添加这个.cn域名。

但是我做到这一步就死活添加不了我的这个.cn域名,难道这种方法已经不能再用了?最后发现Google Apps虽然不支持.cn域名,但是如果你把它改成.CN,就可以注册了。我彻底的囧了,这究竟是Google大意了还是里面另有文章...

在GAE中使用Favicon

首先需要把favicon上传到一个静态目录里:

- url: /images
static_dir: images

然后在head标签中加入:

<link href="/images/favicon.ico" rel="shortcut icon" type="image/x-icon">

在app.yaml中指定favicon的位置:

- url: /favicon.ico
static_files: images/favicon.ico
upload: images/favicon.ico
mime_type: image/x-icon

一个在线制作favicon的工具,一般来说合成后的ico文件最好是包含16x16和32x32两种像素的,16x16可以显示在浏览器的地址栏而32x32则可以显示为桌面快捷方式。

利用google提取favicon,像这样:
http://www.google.com/s2/favicons?domain=jieblog.appspot.com

About

JIEblog是一个简单的blog系统,采用appengine+django开发。
我的联系方式:lucidanui#gmail.com

Creative Commons 3.0 BY