第一部分:Django与Ajax:介绍和安装
近来我开始向正在用Django开发的一个项目中添加Ajax技术,开始有点坎坷。有关于这方面可用的文档资料几乎找不到。这里所写的文章就算是我为改变这种资料贫乏的现状所做的一点微薄的努力吧。
我将分6个部分来介绍使用Ajax和Django创建动态网站,这篇文章是第一部分。
第一部分:Django与Ajax:介绍和安装
第二部分:Django与Prototype:Ajax Updater(动态更新内容)
第三部分:Django与Prototype:Ajax Request(send data out of band)
第四部分:Django与Script.aculo.us:Sortables(Drag and Drop)
第五部分:Django与Script.aculo.us:Visual Effects(Web2.0 Kitsch)
介绍与安装
这篇文章将逐步的让你获得本教程中其它章节所用到的一些库
。这里将它分为两部分:第一部分是对安装的一个快速概述-这应该足以让一名有Django经验的用户配置他的系统-在概述之后我将给那些Django开发新手做一个循序渐进的安装讲解。(只要你已经看完了这个Django教程,应该是可以很好的理解这篇文章的)
安装概述
我们需要做的第一件事情就是获取Protoculouse库
,它是结合了Prototype和Script.aclo.us,并被高比例压缩的一个库。从这里下载Protoculous库。
在你下载的Protoculous库文件名中会标明多种的版本号数字,这里我选用的是protoculous-1.0.2-packed.js这个版本的(因为文章的发表时间不同,可能会有各种不同的版本号)。你需要将protoculous-1.0.2-packed.js文件放到可以静态的使用它的位置。
下一步你需要把protoculous库的引用添加到项目的base模板中(你一定在每个项目中都使用了一个base模板,对吗?)。我的base模板的相关行像下面这样:
{% block javascript %}
<script type="text/javascript" src="http://127.0.0.1/media/protoculous-1.0.2-packed.js"></script>
{% endblock %}
这段代码被放到了templates文件夹中ajaxapp/base.html文件的header部分。说到文件夹,如果你按照我的文件夹的层次来安排,整个过程就会变得相当容易,但如果你不按我的文件夹层次来安排,可能或多或少的需要做一些琐碎的变化。
我的文件夹层次
在ajaxproject文件夹中有一个ajaxapp应用文件夹,还有一个templates文件夹。在templates文件夹中还有一个叫ajaxapp的文件夹。
这就是你所需要做的。如果你觉得上面说的有些太快了,那下面我将逐步的对它们进行详细的介绍。
循序渐进的安装过程
安装Django
我们需要的第一个东西就是Django。如果你没有从Subversion中签出的版本,那么你得先去签出(如果你没有使用Subversion(在命令行中输入svn进行签出),那么就去获取Django的最新安装包吧。安装包与Subversion版本不一致的地方可能是一个issue)。从Subversion中签出django包使用下面的命令:
下载完成后你需要使用下面的命令去安装它们:
cd trunk
python setup.py install
你要使用相应的python版本去安装Django库
,如果你的服务器上有多个版本的Python,那么你需要分别对它们进行安装:
python2.4 setup.py install
python2.5 setup.py install
安装Protoculous
Protoculous非常容易获取,Script.aculo.us和Prothotype都我们都会用到。从下载页面上仅需要获取z
ip文件,它包含两个的库,并用高压缩比将它们压缩到一个文件中。这个文件中会包含不同的版本号,我们将使用protoculous-1.0.2.packed.js这个版本。
安装XAMPP
我们将使用XAMPP来为我们的静态文件服务。它比修改urls
.py文件要更容易请求得到某些静态文件。这里下载XAMPP。它包含一个标准的安装程序("double click and if doesn't work its someone else's fault" variety.)。
设置XAMPP
你现在打算要运行XAMPP了,启动之后,你可能就要想在上面打开它的Apache服务了。你还需要决定到htdocs文件夹(这是Apache服务器在XAMPP中用来输出内容的文件夹)的绝对路径。我的路径是'/Applications/xampp/xamppfiles/htdocs/',但你的可能会与我的不同(取决于你的操作系统)。在文件夹里创建一个名叫"ajaxproject"的文件夹。然后复制一个protoculous-1.0.2-packed.js文件到你刚刚创建的中文件夹中。
设置Django
第一步需要在Django中创建一个项目。进到你想要创建项目的目录然后输入:
django-admin.py startproject ajaxproject
现在我们来创建以后会用到的文件夹。在ajaxproject文件夹中创建一个templates文件夹,在templates文件中再创建一个ajaxapp文件夹。然后开始修改settings.py文件。
设置settings.py
在我们的开发环境中将使用SQLite作为数据库
,因此我们需要在项目中安装数据库。进到你刚刚创建ajaxproject文件夹中打开settings.py文件。数据库配置就像这个样子(绝对路径可能因为操作系统不同而与我的有差异):
DATABASE_ENGINE = 'sqlite3′
DATABASE_NAME = '/Users/will/ajaxproject/ajax.db'
DATABASE_USER = "
DATABASE_PASSWORD = "
DATABASE_HOST = "
DATABASE_PORT = "
接下来你就要根据本地XAMPP来修改MEDIA_ROOT和MEDIA_URL设置了。根据你安装XAMPP的media文件夹的路径不同,你的设置也会略有不同,但它们看起应该差不多是这个样的:
MEDIA_ROOT = '/Applications/xampp/xamppfiles/htdocs/ajaxproject/'
MEDIA_URL = 'http://127.0.0.1/ajaxproject/'
让我们把Django的管理程序也添加进来,我们随后将会创建的应用程序ajaxapp也要放到INSTALLED_APPS中。你的INSTALLED_APPS应该像这样:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'ajaxproject.ajaxapp',
)
我们最后修改settings.py来声明templates文件夹的位置。确切的路径取决于你早些时候创建的文件夹的位置。
TEMPLATE_DIRS = (
"/Users/will/ajaxproject/templates",
)
我们已经完成了对settings.py文件的修改,现在可以关掉它并继续往下进行了。
创建我们的应用
现在我们来创建在settings.py文件中已经包含了的"ajaxapp"应用(在ajaxproject文件夹中运行下面的命令行)。
python manage.py startapp ajaxapp
创建数据库:
python manage.py runserver
如果一切都能正常运转,你会看到一个Django友好的占位页面。真是太神奇了。
设置urls.py文件
我们将需要在做其它修改的时候一并对urls.py文件进行相应的修改。我们需要告诉它ajaxapp这个应用转换url所需要的相关urls列表。
from django.conf.urls.defaults import *
urlpatterns = patterns(",
(r'^admin/', include('django.contrib.admin.urls')),
(r'^', include('ajaxproject.ajaxapp.urls')),
)
我们同时也需要将urls.py复制一份到ajaxapp文件夹中。
我们将会在后面的教程中对ajaxapp/urls.py进行修改,但我们现在不会把它搞乱。
创建base模板
安装的最后部分就是创建一个base.html模板文件
,其它所有模板都会从这个文件中进行扩展。在项目中有一个base模板是一个不错的做法,在这种情况下它让我们只导入一次javascript库就可以了。我们的base.html文件将被放在ajaxproject/templates/ajaxapp/文件夹下,并被命名为.....base.html。
<html lang=en>
<head>
{% block javascript %}
<script type="text/javascript" src="http://127.0.0.1/ajaxproject/protoculous-1.0.2-packed.js"></script>
{% endblock %}
<title> {% block title %} Pastie Lobby {% endblock %} </title>
</head>
<body>
{% block content %}{% endblock content %}
</body>
</html>
完成安装
好啦,我们现在完成了对ajaxproject项目和ajaxap
p应用的设置。我们也为静态文件设置了XAMPP。我们已经为下一步实际的Ajax开发做好了准备工作。点击这里进入到教程的第二部分。
第二部分:Django和Prototype:(动态更新内容)
Ajax的一个通常用途是更新你网站页面的一部分而不必重新加载整个页面。这项功能可以使用Prototype包中的Ajax.Updater()来轻松完成。你可以从
这里获取已完成的示例源代码。
Ajax.Updater的语法和目的
首先,让我们先来看一下它的语法(所有的客户端编码都要用javascript完成,但如果你以前没有做过任何javascript开发也不要被吓倒,因为它非常简单)。
new Ajax.Updater(‘id_to_update’, ‘url_to_send_to’, options)
第一个参数是你打算要更新的html元素的id.例如你可能会创建一个像这样的div:
<div id="edit_div"></div>
第二个参数是你要发送消息的URL。通常它就像“edit/update/”这样,我们稍后将通过例子将它一点一点的具体化。
第三个参数是一个包含了指定项的字典,通常你要指定它是一个异步更新(否则你的网页将被冻结,直到接收到回应,这样不太符合我们需要的用户接口特性),并且你要指定如何发送数据(尽管你不是经常用到发送数据,但如果你需要那么做,你将会用到POST)以及POST的参数。
因此,使用Ajax.Updater的时候需要像下面的例子一样填写参数:
<script type="text/javascript">
function update_div() {
new Ajax.Updater(‘my_div’, ‘/update/’, {asynchronous:true})
}
</script>
<div id="my_div" onclick="update_div();">The list is empty.</div>
这段例程将会向URL /update/ 发送一个更新请求,并且使用 /update/ 返回的html内容来替换my_div中的内容。
现在让我们来做一个实际的例子。
在Django应用中使用Ajax.Updater
我们打算创建一个如何在Django中使用Ajax.Updater的简单示例。我们的网页在开始的时候显示一个0和一个1,在每次你单击包含着0和1的这个div的时候就会显示Fibonacci序列的下一个值(不用重新加载整个页面)。
修改urls.py
首先我们需要修改ajaxapp/urls.py文件。我们将要创建两个链接,第一个将用来显示我们的页面,第二个是用来转换更新请求的链接。你的urls.py(在ajaxproject/ajaxapp/中的那一个)要像这样修改:
from django.conf.urls.defaults import *
urlpatterns = patterns(‘ajaxproject.ajaxapp.views’,
(r‘^$’, ‘index’),
(r‘^refresh/$’, ‘refresh’),
)
创建视图
我们的视图文件非常简单,它将引用到一些还没有被创建的模板,但不用介意(我们将在下一步进行创建)
from django.shortcuts import render_to_response
FIB = [0,1]
def get_fib_sequence():
global FIB
FIB.append(FIB[-1] + FIB[-2])
return FIB
def index(request):
return render_to_response("ajaxapp/index.html",
{ ‘fib_sequence’ : [0,1] }
)
def refresh(request):
fib_sequence = get_fib_sequence()
return render_to_response("ajaxapp/fib.html",
{ ‘fib_sequence’ : fib_sequence }
)
为了节省时间,我们将get_fib_sequence函数放到了视图中,这是一种不明智的做法,在实际的开发中我们会将它放到一个单独的文件中。
我们只是在视图中简单的渲染了一下模板并把它们返回-我们没有做更多的处理。这就是Ajax.Updater美好的地方:它将简单的把所返回的任意html插入到指定位置。
创建模板
现在我们来创建在视图中被引用到的两个模板:ajaxapp/index.html和ajaxapp/fib.html。
index.html模板相当简单,它将扩展自我们先前创建的base.html(在本系列文章的第一部分)。它包含了一些javascript,一个header和一个用来装载Fibonacci序列的div(它将被fib.html模板渲染)。ajaxapp/index.html模板就像这样:
{% extends ‘ajaxapp/base.html’ %}
{% block content %}
<script type="text/javascript">
function update_fib() {
new Ajax.Updater(’fib_div’, ‘refresh/’, {asynchronous:true});
}
</script>
<h1> The Fibonacci Sequence </h1>
<div id="fib_div" onclick="update_fib();">
{% include ‘ajaxapp/fib.html’ %}
</div>
{% endblock %}
我们来创建ajaxapp/fib.html模板:
<ul>
{% for entry in fib_sequence %}
<li>{{ entry }}</li>
{% endfor %}
</ul>
再次看来这是一个相当简单的模板。你将发现在Django中你做更多的Ajax时,创建小助手模板真的能使你的生活更轻松。记住,这是一个好的模式。
结束
OK,现在我们写完了模板,就全部完成啦。启动起来开发服务器:
python manage.py runserver
然后你就到网页这里,在0和1的地方点击来查看它的运行结果。
当你准备好的时候你就可以继续本教程
下一部分的学习了。下一部分将说明在不离开当前页面的情况下使用Ajax.Request发送数据或命给Django。
第三部分:Django与Prototype:Ajax Request(非对称模式发送数据)
Ajax另一个常用的功能是发送数据到服务器但不强制用户重新加载他们所在的整个页面。在Django与Ajax教程的第三节中我们将要向Server发送Django生成表单的内容。(Request和Upater不同之处是Requset对象不需要服务器进行应答,下面将更加深入的进行解释。)你可以从这里得到本节例子的源码。
Ajax Request语法和目的
Ajax.Requst负责的是从网页到服务器的单向交流。它大概就像网页说“嗨,这家伙创建了一个帐号,我已经知道该怎么做了,所以不要理会给我的指令”,或者可能像网页说:“server my man, you have a new comment to hold onto until someone can approve it.(你有一条新的评论需要保持直到有人批准它--这句话不太明白是嘛意思)”当你希望使用Ajax.Request从服务器得到一些HTML来填充div,或者从服务器得到任何种类的响应时,它是没有用的,你将什么也得不到。
Ajax.Request的语法为:
new Ajax.Request(‘url/to/send/to’, config)
第一个参数是你发送数据的目标URL,第二个是一个包含配置数据的字典变量。跟Ajax Updater一样你需要指定要发送的数据,发送方式,是否异步(它通常是异步的,除非你和用户有仇…)。这里有两个可能在实际中使用的例子:
var post = ‘id=’ + id;
new Ajax.Request(‘category/remove/’, {asynchronous:true, method:‘post’, postBody:post});
或
new Ajax.Request(‘category/add’, {asynchronous:true, parameters:Form.serialize(form)});
这两个例子中的第二个例子要复杂一些,因为它使用Prototype中的Form库来序列化一个表单。第一次看到它可能会觉得有点混乱,但在我们的例子中将会看一下它到底如何在模板和视图中设置和转化被序列化的表单。
在Django应用中使用Ajax.Request
在文章开始我们就谈到,我们要创建一个有简单表单的页面,当我们按下提交按钮的时候表单就会被发送到服务器。在发送后我们将会使用Prototype的Form库来重置这个表单。
尽管略有牵强,但这个例子的确与真实用例很相似。你已经知道在没有任何服务器指令的时候如何回应某些刺激,但你还是需要将所发生的一切通知服务器。一种情况是当你从一个页面上删除内容的时候:你可以在客户端使用JavaScript从问题中移除元素,但仍必须让服务器知道哪些元素被删除。
总之,让我们开始编码吧。
修改urls.py
我们将在ajaxapp/urls.py文件中添加两个入口。一个将用来显示页面,另一个将用来处理发送过来的已完成表单。
我们把ajaxapp/urls.py修改成这样:
from django.conf.urls.defaults import *
urlpatterns = patterns(‘ajaxproject.ajaxapp.views’,
(r‘^$’, ‘index’),
(r‘^send/$’, ’send’),
)
十分简单。接下来让我们处理Views。
创建视图
我们需要在视图中添加两个函数---index和send。我们也会将表单和视图写在一起(在一个大的工程中最好将模型从视图中独立出来)。
模型会有两个字段,一个character字段和一个textarea字段。我们将通过newforms库来创建它,像下面这样:
class CommentForm(forms.Form):
name = forms.CharField(required=False)
text = forms.CharField(widget=Textarea, required=False)
现在有了(简单的)表单,我们需要去创建两个视图函数。首先,我们需要使用index函数去渲染amaxapp/index.html这个模板,同时还要确保将一个“form”变量传给了它。
def index(request):
form = CommentForm()
return render_to_response("ajaxapp/index.html",{ ‘form’ : form})
我们还需要创建send函数来处理接收到的表单数据。为了简单,我们仅仅向标准输出设备打印一个格式化好的输入文本(也就是说你可以从你的开发服器终端窗口上来看到输出结果)。
def send(request):
post = request.POSTfor key in post.keys():
print "key: " , key , "; value: " , post[key]
实际应用中你可能会根据接收到的数据创建一个新的Model实例,或者可能通过新值来更新现有实例。幸好很容易从表单中获取键值。
请注意,因为我们接收到的是一个通过newforms库创建的、已经被序列化的表单,它很容易使用已经接收到的request.POST数据来转换成为一个已创建的表单的实例。就像下面这样简单:
def send(request):
post = request.POST
form = CommentForm(post)
还不算太坏。如果你用form_for_model方法创建了一个表单将会特别的方便,此时,你可以简单的调用form.save()方法来创建一个新的Model实例。
好了,如果我们把模型和视图函数放在一块,那么整个的views.py文件将会是这样:
from django.shortcuts import render_to_response
from django import newforms as forms
class CommentForm(forms.Form):
name = forms.CharField(required=False)
text = forms.CharField(widget=forms.Textarea, required=False)
def index(request):
form = CommentForm()
return render_to_response("ajaxapp/index.html",
{ ‘form’ : form }
)
def send(request):
post = request.POST
for key in post.keys():
print "key: " , key , "; value: " , post[key]
创建模板
我们这个例子只需要一个简单的模板,它将用来显示前面创建的CommentForm表单,并且它还将有一些辅助的javascript来覆盖表单缺省的提交处理。这个模板扩展自我们在教程第一部分创建的ajaxapp/base.html模板。
{% extends ‘ajaxapp/base.html’ %}
{% block content %}
<script type="text/javascript">
function send_form(form) {
new Ajax.Request("send/", {asynchronous:true, parameters:Form.serialize(form)});
Form.reset(form);
return false;
}
</script>
<h1> Submit Comments </h1>
<form method="post" action="." onsubmit="return send_form(this);">
<table>
{{ form }}
<tr>
<td></td>
<td>
<input type="submit" value="Send!" />
</td>
</tr>
</table>
{% endblock %}
注意我们是如何来覆盖表单的onsubmit缺省方法的。因为我们在调用中返回了false,所以缺省的提交机处理将永不被触发。此外,我们还使用了Prototype的Form库中的一个有用的方法在发送完数据后来重置表单。
我们还使用了Form库中的一个便利的方法来序列化这个表单。可以使用文章开头附近第一个例子的语法来创建你自己任意的post strings…如果行的话它会非常容易被序列化。
结束
现在我们已经完成了urls的添加,模板的创建,以及视图的编码:一切搞定!
运行一下开发服务器
python manage.py runserver
往表单字段里输入一些数据然后点击提交按钮。你将看到所发出的消息会从开发服务器的终端窗口上被打印出来。
花一些时间来多加练习,后面还有第四部分等着你呢。我将在第四部分中介绍使用Scriptaculous来拖放列表。