gae meets django
TRANSCRIPT
使用Django创建Google App Engine应用
• Google App Engine介绍
• Django介绍
• 代码示例
Google App Engine介绍
什么是Google App Engine• Google的Web Hosting服务
•将你的Web应用部署到Google的基础设施之上
•使你的应用能够自动Scaling和load balancing
•提供数据存储服务
•集成了Google User认证和Gmail等服务
运行环境和限制• Python 2.5.2
•内置Django 0.96.1,并支持所有支持CGI的框架(以及任何使用CGI适配器的WSGI框架)
•运行在Sandbox中,不能访问文件系统,不能建立socket,不支持cron job,不能创建子进程
•限定时间内必须返回response
•应用必须是纯Python,不支持C的扩展
存储-Datastore•基于Google BigTable,分布式存储服务
•面向对象,非关系型数据库,不支持ORM
•相同Model可以有不同的属性
•支持查询,排序,事务
•不支持join, sum, avg等,不支持存储过程
•每次查询最多返回1000条记录
•全文检索?
App Engine Service
• Google帐号认证
• Gmail(发送email)
• URL Fetch
• Memcached
• Image (PIL)
价格(免费部分)Fixed Quota Per Day Usage Quotas
大约500万PV/月
价格(收费部分)
• $0.10 - $0.12 per CPU core-hour
• $0.15 - $0.18 per GB-month of storage
• $0.11 - $0.13 per GB outgoing bandwidth
• $0.09 - $0.11 per GB incoming bandwidth
申请Google App Engine• http://appengine.google.com/
•通过Gmail帐号
•通过短信认证
•域名: http://yourapp.appspot.com
•可以通过Google Apps绑定自己的域名
用途
•学习Web开发
•尝试各种idea, 减少startup的前期投入成本
•解决scalability问题
• App Gallery http://appgallery.appspot.com/
未来计划•对更多语言的支持
•收费计划
•大数据量的上传和下载
•离线处理
•数据导入/导出
Django简介
Django简介
•一个基于Python的full-stack Web框架
• ORM, URL mapping, admin interface, template, middleware, i18n, cache...
•很快很强大
为什么用Django(而不是webapp)
• Google App Engine Helper for Django
•功能更强大
•可移植性
项目示例-Blog系统
项目名称 - OnlyPython
创建开发环境
• 下载Google App Engine SDK
http://code.google.com/appengine/downloads.html
• 从SVN下载最新的Django源代码
http://code.djangoproject.com/svn/django/trunk/
• 下载Google App Engine Helper for Django
http://code.google.com/p/google-app-engine-django/
项目目录结构--- appengine-django (app engine helper for django 源文件目录)
--- django (django源文件目录)
--- onlypy (项目代码目录)
--- static (静态文件目录,存放js, css, 图片等)
--- app.yaml (app engine配置文件)
--- index.yaml (app engine索引配置文件)
--- main.py (app engine的启动脚本)
--- manage.py (Django的管理脚本)
--- settings.py (项目配置文件)
--- urls.py (URL mapping)
app.yamlapplication:onlypython
version:1
runtime:python
api_version:1
handlers:
‐url:/static
static_dir:static
‐url:/.*
script:main.py
main.pyimportosimportsysimportlogging
fromappengine_djangoimportInstallAppengineHelperForDjangoInstallAppengineHelperForDjango()
#GoogleAppEngineimports.fromgoogle.appengine.ext.webappimportutil
#ImportthepartofDjangothatweusehere.importdjango.core.handlers.wsgi
defmain():#CreateaDjangoapplicationforWSGI.application=django.core.handlers.wsgi.WSGIHandler()
#RuntheWSGICGIhandlerwiththatapplication.util.run_wsgi_app(application)
if__name__=='__main__':main()
settings.pyTIME_ZONE='UTC'
MIDDLEWARE_CLASSES=(
'django.middleware.common.CommonMiddleware',
'appengine_django.auth.middleware.AuthenticationMiddleware',
)
ROOT_URLCONF='urls'
ROOT_PATH=os.path.dirname(__file__)
TEMPLATE_DIRS=(
os.path.join(ROOT_PATH,'onlypy/templates')
)
INSTALLED_APPS=(
'appengine_django',
'django.contrib.auth',
'onlypy.blog',
)
TODO: 添加Blog
models.pyfromgoogle.appengine.extimportdb
classCategory(db.Model):name=db.StringProperty()def__str__(self):returnself.name
classPost(db.Model):author=db.UserProperty()title=db.StringProperty(required=True,verbose_name=u'标题')tag=db.StringProperty(verbose_name=u'标签')content=db.TextProperty(required=True,verbose_name=u'内容')
create_time=db.DateTimeProperty(auto_now_add=True)update_time=db.DateTimeProperty(auto_now=True)category=db.ReferenceProperty(Category,required=True,verbose_name=u'类别')
is_published=db.BooleanProperty(verbose_name=u'已发布')
defget_absolute_url(self):return'/post/%s/'%self.key().id()
forms.pyfromgoogle.appengine.ext.dbimportdjangoformsasformsfrommodelsimportPost
classPostForm(forms.ModelForm):classMeta:model=Postexclude=['author']
views.pydefadd_post(request):
ifrequest.method=='GET':form=PostForm()ifrequest.method=='POST':form=PostForm(request.POST)ifform.is_valid():post=form.save()post.author=users.get_current_user()post.put()returnHttpResponseRedirect('/post/add/')
returnrender_to_response('blog/add_post.html',{'form':form},context_instance=RequestContext(request))
add_post.html{%extends"base.html"%}
{%blockcontent%}<h1>添加新文章</h1>
<formname="mainForm"method="post"action="">{{form.as_p}}<inputtype="submit"value="保存"/>
</form>{%endblock%}
urls.pyfromdjango.conf.urls.defaultsimport*
urlpatterns=patterns('onlypy.blog.views',(r'^post/add/$','add_post'),)
Run• cd /yourpath/onlypython/
• python ./manage.py runserver 127.0.0.1:8000
TODO: 显示Blog列表
views.pydeflist_post(request):
posts=Post.all().order('‐create_time')if(notis_admin()):posts=posts.filter("is_published",True)returnobject_list(request,queryset=posts,allow_empty=True,template_name='blog/list_post.html',extra_context={'is_admin':is_admin()},paginate_by=20)
index.yamlindexes:
‐kind:Postproperties:‐name:is_published‐name:create_timedirection:desc
list_post.html{%extends"base.html"%}{%loadmarkup%}{%loadpaginator%}
{%blockcontent%}{%forpostinobject_list%}<tableborder="0"cellspacing="0"cellpadding="0"width="100%"><tr><tdvalign="top"><h1style="margin‐bottom:2px;"><ahref="/post/{{post.key.id}}">[{{post.category.name}}]{{post.title}}{%ifpost.is_published%}{%else%}(未发布){%endif%}
</a></h1><pstyle="padding:0px;margin:0px;"class="small_font">类别:<ahref="/category/
{{post.category.key.id}}/">{{post.category.name}}</a><spanstyle="padding‐left:10px;">{{post.author.nickname}}写于{{post.create_time|date:"Y‐M‐dH:i"}}</span>
</p></td></tr></table><divstyle="padding‐left:30px;">{{post.content|markdown}}</div>{%endfor%}{%paginator%}{%endblock%}
urls.pyfromdjango.conf.urls.defaultsimport*
urlpatterns=patterns('onlypy.blog.views',(r'^post/add/$','add_post'),(r'^$','list_post'),)
项目信息• 项目代码 http://code.google.com/p/onlypy/
• 项目演示 http://www.onlypython.com
Q&A