首页 » 科技 » 使用app-engine-patch发挥Django的威力

使用app-engine-patch发挥Django的威力

利用app-engine-patch在appengine中使用Django.

介绍

在Django框架可以让一个web开发者的生活为更轻松。它照顾到了很多Web开发者所必须处理的共同问题,并提供了许多“可服用的组件” -您可以插入到您的项目重的严格测试过的代码。

由于一些概念上的差异,一些Django特性不能在Google App Engine上工作。其中一个主要的特性就是Django的ORM,因为AppEngine的数据存储(Datastore)不同于Django的ORM所基于的传统的关系数据库模型。app-engine-patch是一个围绕在缺乏对Django ORM的支持所带来的限制之上,旨在提供Django所具有的全部功能的项目。该项目可以在这里找到:http://code.google.com/p/app-engine-patch/

在本文中,我们将列举一些理由来说明为什么你可能需要在你的项目中考虑使用Django和app-engine-patch,然后用一个应用程序来论证app-engine-patch的威力。此示例支持谷歌和非谷歌帐户的认证。

使用Django而不是Webapp的理由

使用Django而不是Google App Engine的webapp框架的理由是,Django已经被许多类型的Web应用程序广泛使用多年。此外, Django有着广泛的开发者社区。有许多博客讨论Django ,有一个非常常用的邮件列表,以及#django的IRC频道。

Webapp是专为Google App Engine开发的,并且尚未建立所有这类社区的支持。 Django也已成为“标准”的Python网络框架。还有其他一些伟大的框架,如Pylons或cherrypy ,其中大部分也可以在App Engine上工作,但Django当下无疑是最为流行的。它提供了对大型项目而言的许多重要的特性,如内置的国际支持,缓存,认证会话,中间件支持等等。 Webapp缺少这些大部分的特性。如果你需要他们,你必须自己去创造轮子。最后,Django让你越来越少地依赖于App Engine。如果您使用webapp ,你不能轻易地切换到另一个系统,至少在目前。


使用app-engine-patch的理由

app-engine-patch从Django世界移植了尽可能多的东西到App Engine。您将不需要多少调整就可以使用大量的可重用的Django组件。移植现有的Django 代码到App Engine也将容易得多。app-engine-patch也将减少传统的Django和用于App Engine上的Django之间的差异。所以,如果出于某种原因,在未来如果您想从App Engine切换到自己的主机托管方案,将在很大程度上减少了需要工作。同时它可以让您受益于支持庞大的Django社区支持。app-engine-patch还附带一个叫做ragendja的库 ,提供更多的特性,包括事务装饰器和全局模板标记。app-engine-patch所提供的特性的全部清单在项目的主页: http://code.google.com/p/app-engine-patch/

与App Engine Helper for Django通过定制的BaseModel模拟了Django的models不同,app-engine-patch坚持使用常规的Datastore API 。这是因为事实上几乎不可能真正的通过App Engine Datastore模仿Django models,这样做也获得了可以在第一时间使用Datastore 最新发布特性的优点。

app-engine-patch提供了多种App Engine Helper缺失的的Django特性。进一步的细节在该项目的主页。另一个重要区别是,app-engine-patch支持最新的稳定版本Django ,而Helper支持的是版本0.96 (svn trunk支持1.0版)。

获得 app-engine-patch

为了使你容易启动一个项目,app-engine-patch分发为一个自包含的示例项目。您可以浏览项目主页获得最新版本: http://code.google.com/p/app-engine-patch/downloads/list 。在本文翻译之时,1.1beta1是最新的版本。

App-engine-patch 需要 the App Engine SDK 才能工作: http://code.google.com/appengine/downloads.html.

在Windows和Mac OS X上 ,你必须使用安装程序所提供的SDK 。如果你是在Linux上,把SDK的文件夹中包含在您的PATH环境变量或在/usr/local/google_appengine 。请确保SDK的文件夹命名为google_appengine 。

要启动样例项目,更改appengine-patch-sample文件夹,并从命令行执行manage.py runserver。app-engine-patch将在幕后启动App Engine开发服务器,现在你已经准备好了。如果您从浏览器访问 http://localhost:8000,您将看到示例项目中的活动。该示例演示了部分Django的generic views的使用,generic views为常见任务如创建或编辑model实例等提供快捷方式。

一个实际的例子

为了论证app-engine-patch提供的一些特性,我们将使用Django重写这个留言本的应用程序:http://code.google.com/appengine/docs/python/gettingstarted/usingdatastore.html 。我们会使用generic views,并且为谷歌用户和非谷歌用户提供用户认证。

初看起来可能有与Django 的目录组织有一些间接关联。不过结构是有益的,因为它会帮助您保持你的代码结构化和可复用,这对较大的项目很重要。

Django项目结构

在Django 中,一个项目被分为几个应用包。以某种方式创建功能独立于给定项目的特定应用是有可能的。因此,您可以封装成插件在多个Django项目中使用。比如,一个博客的标记库就可以做一个易用包。

除了应用, Django项目还包含一个全局设置文件和一个定义URL在框架中处理方式的根URL配置文件。应用可以有额外的URL配置,也会被加入到主URL配置文件。 Django 的模板以类似的方式工作。可以有所有应用公用的全局模板,也可以有特定应用自己的模板。

但我们已经讲的够多啦,还是做点儿实际的工作吧!

配置你的项目

首先,我们配置app-engine-path的安装,以便它准备就绪部署。打开Google App Engine的app.yaml配置文件,并替换应用称许域为您的应用程序id。您可以现在就执行manage.py update部署您的应用程序部署到Google App Engine。

如果你看一下示例项目的内容,您将看到示例应用程序放在一个叫myapp的目录中 。我们来创建一个另一个应用,也就是留言簿。创建一个文件夹命名为guestbook,并创建这些文件:

  • __init__.py - Python会把包含这个文件的文件夹视为一个包
  • urls.py - 特定应用的URL配置.它控制在给定的URL上执行视图(请求处理request handlers)
  • models.py - 应用的数据存储模型
  • views.py -  包含视图,Django中处理请求逻辑的术语
  • templates - 包含你的应用的HTML模板的文件夹

让我们的安装应用到我们的项目。要做到这一点,需要在settings.py中的INSTALLED_APPS列表中把你的应用名称包含进来

INSTALLED_APPS =(
   
...
   
'guestbook',
)

如果您正使用配合Django使用关系型数据库,你现在必须运行manage.py syncdb创造必要的数据库表。不过在App Engine中这一切都是多余的。

现在让我们把留言簿应用集成进全局URL路由。修改项目的global/urls.py 文件,使其包含如下行:

urlpatterns = patterns('',
   
...
   
(r'^guestbook/', include('guestbook.urls')),
)

现在如果你访问任何以/guestbook/开头的网址,系统将会在应用特定URL配置文件/guestbook/urls.py中寻找匹配的请求。


创建models

打开你的/guestbook/models文件,创建如下的数据库模型:

from google.appengine.ext import db
from django.contrib.auth.models importUser

classGreeting(db.Model):
    author
= db.ReferenceProperty(User)
    content
= db.StringProperty(multiline=True)
    date
= db.DateTimeProperty(auto_now_add=True)

用户model将会由app-engine-patch给我妈提供,所以这里不必特意指定了。因为我们希望Django和Google用户认证可以
生效,所以需要在你的设置中激活中间件并制定正确的用户model.在/settings.py中替换Django的认证中间件:

# Replace Django's AuthenticationMiddleware with HybridAuthenticationMiddleware.
MIDDLEWARE_CLASSES
=(
   
...
   
'ragendja.auth.middleware.HybridAuthenticationMiddleware',
   
...
)

并添加

# Change the User model class
AUTH_USER_MODULE
='ragendja.auth.hybrid_models'

# Add google_login_url and google_logout_url tags
GLOBALTAGS
=('ragendja.templatetags.googletags',)

到文件的末尾。

这就是一切。真不敢相信,但这是真的!现在你已经可以同时使用Django和Google的用户认证了。另外,你还可以启用模板标记
以渲染随时出现的Google登录和注销链接。要尝试的话,创建一个
/guestbook/templates/index.html文件

<html>
<head>
</head>
<body>compliant
<divclass="login">
  {% if user.is_authenticated %}
    Welcome, {{ user.username }}
   
<ahref="{% google_logout_url request.get_full_path %}">Logout</a>
  {% else %}
   
<ahref="{% google_login_url request.get_full_path %}">Login</a>
  {% endif %}
</div>
</body>
</html>

并且在/guestbook/urls.py中设置URL路由:

  from django.conf.urls.defaults import*
 
  urlpatterns
= patterns('',
     
(r'^$','django.views.generic.simple.direct_to_template',{'template':'index.html'}),
  )

如果你现在在浏览器中加载http://localhost:8000/guestbook/ ,你要看到google认证的请求。不难吧?

注意: 这里你通过渲染html模板的同时也见到了Django的generic views是如何生效的.


提供非Google用户的认证

现在让我们为没有Google账户的人员添加认证.我们再次将尽可能的利用generic views,因为使用他们更简单而且比你自己手写
views出错的可能性更小。

第一件事情就是让用户可以登录,还记得我们在settings.py中设置的AUTH_USER_MODULE指令么?这将执行一些魔力,使我们能够
导入通常的Django 用户model,而且还有混合身份验证的支持。

注册用户

为了让用户可以注册账户,在/guestbook/views.py中添加如下代码:

from django.contrib.auth.models importUser
from django.contrib.auth.forms importUserCreationForm
from django.shortcuts import render_to_response
from django.http importHttpResponseRedirect

def create_new_user(request):
    form
=UserCreationForm()
   
# if form was submitted, bind form instance.
   
if request.method =='POST':
        form
=UserCreationForm(request.POST)
       
if form.is_valid():
            user
= form.save(commit=False)
           
# user must be active for login to work
            user
.is_active =True
            user
.put()
           
returnHttpResponseRedirect('/guestbook/login/')
   
return render_to_response('guestbook/user_create_form.html',{'form': form})

这里我不会去讲太多细节,因为它实际上与标准Django没什么区别。app-engine-patch在幕后处理了创建用户的细节,包括使用
App Engine的datastore代替通常Django中使用的数据库表。

UserCreationForm自动由Django提供。这个view创建了一个表单对象,并把它传给一个叫user_create_form.html的模板。
当一个表单通过POST请求提交后,一个用户被创建,接着用户将被重定向到登录页面。如果表单是无效的,将提供一个有意义的错误信息
提示.

为了看到这个操作,还有两件事得做。首先把"create_new_user方法挂到你的URL配置文件/guestbook/urls.py中去:

urlpatterns = patterns('',
   
...
   
(r'^signup/$','guestbook.views.create_new_user'),
)

并创建一个模板 /guestbook/templates/user_create_form.html:
<html>
<head>
</head>
<body>
<formaction="."method="post">
 
<table>
    {{form.as_table}}
 
</table>
  You can also login with your
<ahref="{% google_login_url "/guestbook" %}">Google account.</a>
 
<inputtype="submit"value="submit">
</form>
</body>
</html>

Django用户登录

 为免你像我一样憎恨在显示器前阅读长文本,我将加快脚步.添加这个到你的/guestbook/urls.py:

urlpatterns = patterns('',
   
...
   
(r'^login/$','django.contrib.auth.views.login',{'template_name':'guestbook/user_create_form.html'}),
)

请注意我已经重用了用户创建的模板,以使你避免再次copy&paste.就是这样了。创建一个新的用户或者打开 http://localhost:8000/guestbook/login/ 看看generic view是如何生效的。

注意:如果没有特别规定的话,成功登陆后登陆的generic view将跳转到/accounts/profile.你可以在settings.py里面设置
LOGIN_REDIRECT_URL = "/guestbook/"来改变它,不然登陆的用户将会看到404消息页面.

注销链接当前只在google注销用户面前显示。为了给Django注销用户提供,只需在"/guestbook/urls.py"里面加入如下generic view:

#the "logout" generic view expects a template logged_out.html. Using this generic view, you can redirect the user to
#another page after log out.
(r'^logout/$','django.contrib.auth.views.logout_then_login',{'login_url':'/guestbook/'}),

并且替换/guestbook/templates/index.html 如下:

{%if user.is_active %}<a href="/guestbook/logout">
{%else%}<a href="{% google_logout_url "/guestbook/" %}">
{% endif %}Logout</a>

因为Google用户没有 is_active 这个域,所以上述例子可以生效。存在一些更好的方法检查我们正在处理的是哪一类型的用户,但是对于我们
的案例来说这个更简单并且可以工作。app-engine-patch的库版本中包括区分不同用户类型的方法。

让guestbook工作

现在让我们添加创建和显示guestbook条目的能力。添加如下代码到/guestbook/views.py的末尾:

from django.views.generic.list_detail import object_list
from django.views.generic.create_update import create_object
from django.contrib.auth.decorators import login_required
from guestbook.models importGreeting

def list_entries(request):
   
return object_list(request,Greeting.all())

@login_required
def create_entry(request):
   
# Add username to POST data, so it gets set in the created model
   
# You could also use a hidden form field for example, but this is more secure
    request
.POST = request.POST.copy()
    request
.POST['author']= str(request.user.key())
   
return create_object(request,Greeting, post_save_redirect='/guestbook')

并更改/gustbook/urls.py:

from django.conf.urls.defaults import*

urlpatterns
= patterns('',
   
(r'^$','guestbook.views.list_entries'),
   
(r'^sign/$','guestbook.views.create_entry'),
   
(r'^signup/$','guestbook.views.create_new_user'),
   
(r'^login/$','django.contrib.auth.views.login',{'template_name':'guestbook/user_create_form.html'}),
   
(r'^logout/$','django.contrib.auth.views.logout_then_login',{'login_url':'/guestbook/'}),
)

这个generic view 期望你创建一个/guestbook/templates/greeting_list.html的模板:

<html>
<head>
</head>
<body>
<divclass="login">
  {% if user.is_authenticated %}
    Welcome, {{ user.username }}
    {% if user.is_active %}
     
<ahref="/guestbook/logout">
    {% else %}
     
<ahref="{% google_logout_url "/guestbook/" %}">
    {% endif %}Logout
</a>
  {% else %}
   
<ahref="{% google_login_url request.get_full_path %}">Login with your Google account</a><br>
   
<ahref="/guestbook/login">Login with your normal account</a><br>
   
<ahref="/guestbook/signup">Sign up</a><br>
  {% endif %}
</div>
{% for object in object_list %}
 
<p>{{object.author.username}}: {{object.content}}</p>
{% endfor %}
<ahref="/guestbook/sign/">Add entry</a>
</body>
</html>

and /guestbook/templates/greeting_form.html:

<html>
<head>
</head>
<body>
<formmethod="POST"action=".">
  {{form.content}}
 
<inputtype="submit"value="create">
</form>
</body>
</html>
 登录留言现在已经能够工作了。我们已经为/guestbook/修改了generic view提供的index.html模板 ,通过引用相关函数增加了显示留言列表功能。Django提供的login_required装饰器能确保用户必须登录才能访问所请求的视图。装饰器默认登录网址为/accounts/login/ ,可以在settings.py文件里修改:

    LOGIN_URL = '/guestbook/login'

注意:如果想要匿名用户能够登录留言,将考虑的事实是匿名用户不存在关键属性(key-attribute)。


结论

    现在我们已经完成了一个非常基本的项目 ,让Google用户和非Google用户都可以登录并添加留言的guestbook,我们广泛使用了genric view,以证明他们是如何使常见任务变得容易得多。如果你是第一次在GAE上使用Django,我希望这篇文章就足以让您可以开始使用.如果您已经是一个熟练的Django用户,我希望它能够让你产生兴趣!


【本文翻译仅为外语学习及阅读目的,原文作者个人观点与译者及译言网无关】

1

评论