第一部分: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)
我將分6個部分來介紹使用Ajax和Django創建動態網站
第一部分:Django與Ajax:介紹和安裝
第二部分:Django與Prototype:Ajax Updater(動態更新內容)
第三部分:Django與Prototype:Ajax Request(send data out of band)
第四部分:Django與Script.aculo.us
第五部分:Django與Script.aculo.us
介紹與安裝
這篇文章將逐步的讓你獲得本教程中其它章節所用到的一些庫。這里將它分為兩部分:第一部分是對安裝的一個快速概述-這應該足以讓一名有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模板的相關行像下面這樣:
我們需要做的第一件事情就是獲取Protoculouse庫
在你下載的Protoculous庫文件名中會標明多種的版本號數
下一步你需要把protoculous庫的引用添加到項目的bas
{% block javascript %}
<script type="text/javascript" src="http://127.0.0.1/media/protoculous-1.0.2-packed.js"></script>
{% endblock %}
<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應用文件夾
這就是你所需要做的。如果你覺得上面說的有些太快了
循序漸進的安裝過程
安裝Django
我們需要的第一個東西就是Django。如果你沒有從Subversion中簽出的版本,那么你得先去簽出(如果你沒有使用Subversion(在命令行中輸入svn進行簽出),那么就去獲取Django的最新安裝包吧。安裝包與Subversion版本不一致的地方可能是一個issue)。從Subversion中簽出django包使用下面的命令:
安裝Django
我們需要的第一個東西就是Django。如果你沒有從Subver
下載完成后你需要使用下面的命令去安裝它們:
你要使用相應的python版本去安裝Django庫,如果你的服務器上有多個版本的Python,那么你需要分別對它們進行安裝:
cd trunk
python setup.py install
python setup.py install
python2.4 setup.py install
python2.5 setup.py install
python2.5 setup.py install
安裝Protoculous
Protoculous非常容易獲取,Script.aculo.us和Prothotype都我們都會用到。從下載頁面上僅需要獲取zip文件,它包含兩個的庫,并用高壓縮比將它們壓縮到一個文件中。這個文件中會包含不同的版本號,我們將使用protoculous-1.0.2.packed.js這個版本。
Protoculous非常容易獲取,Script.aculo.us和Prothotype都我們都會用到。從下載頁面上僅需要獲取z
安裝XAMPP
我們將使用XAMPP來為我們的靜態文件服務。它比修改urls.py文件要更容易請求得到某些靜態文件。這里下載XAMPP。它包含一個標準的安裝程序("double click and if doesn't work its someone else's fault" variety.)。
我們將使用XAMPP來為我們的靜態文件服務。它比修改urls
Firebug
雖然Firebug不是必須的,但當你開始在使用html
設置XAMPP
你現在打算要運行XAMPP了,啟動之后,你可能就要想在上面打開
設置Django
第一步需要在Django中創建一個項目。進到你想要創建項目的目
django-admin.py startproject ajaxproject
現在我們來創建以后會用到的文件夾。在ajaxproject文件夾中創建一個templates文件夾,在templates文件中再創建一個ajaxapp文件夾。然后開始修改settings.py文件。
設置settings.py
在我們的開發環境中將使用SQLite作為數據庫,因此我們需要在項目中安裝數據庫。進到你剛剛創建ajaxproject文件夾中打開settings.py文件。數據庫配置就像這個樣子(絕對路徑可能因為操作系統不同而與我的有差異):
接下來你就要根據本地XAMPP來修改MEDIA_ROOT和MEDIA_URL設置了。根據你安裝XAMPP的media文件夾的路徑不同,你的設置也會略有不同,但它們看起應該差不多是這個樣的:
創建我們的應用
現在我們來創建在settings.py文件中已經包含了的"ajaxapp"應用(在ajaxproject文件夾中運行下面的命令行)。
創建數據庫:
在我們的開發環境中將使用SQLite作為數據庫
DATABASE_ENGINE = 'sqlite3′
DATABASE_NAME = '/Users/will/ajaxproject/ajax.db'
DATABASE_USER = "
DATABASE_PASSWORD = "
DATABASE_HOST = "
DATABASE_PORT = "
DATABASE_NAME = '/Users/will/ajaxproject/ajax.db'
DATABASE_USER = "
DATABASE_PASSWORD = "
DATABASE_HOST = "
DATABASE_PORT = "
MEDIA_ROOT = '/Applications/xampp/xamppfiles/htdocs/ajaxproject/'
MEDIA_URL = 'http://127.0.0.1/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',
)
'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",
)
"/Users/will/ajaxproject/templates",
)
我們已經完成了對settings.py文件的修改,現在可以關掉它并繼續往下進行了。
創建我們的應用
現在我們來創建在settings.py文件中已經包含了的
python manage.py startapp ajaxapp
創建數據庫:
python manage.py syncdb
讓我們來確定一下所有的配置到現在都能正常運行。首先打開瀏覽器,然后輸入[url]http://127.0.0.1:8000[/url]。
python manage.py runserver
如果一切都能正常運轉,你會看到一個Django友好的占位頁面。真是太神奇了。
設置urls.py文件
我們將需要在做其它修改的時候一并對urls.py文件進行相應的
from django.conf.urls.defaults import *
urlpatterns = patterns(",
(r'^admin/', include('django.contrib.admin.urls')),
(r'^', include('ajaxproject.ajaxapp.urls')),
)
urlpatterns = patterns(",
(r'^admin/', include('django.contrib.admin.urls')),
(r'^', include('ajaxproject.ajaxapp.urls')),
)
我們同時也需要將urls.py復制一份到ajaxapp文件夾中。
cp urls.py ajaxapp/
我們將會在后面的教程中對ajaxapp/urls.py進行修改,但我們現在不會把它搞亂。
創建base模板
安裝的最后部分就是創建一個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>
<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項目和ajaxapp應用的設置。我們也為靜態文件設置了XAMPP。我們已經為下一步實際的Ajax開發做好了準備工作。點擊這里進入到教程的第二部分。
好啦,我們現在完成了對ajaxproject項目和ajaxap
第二部分: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>
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’),
)
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 }
)
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 %}
{% 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>
{% 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/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’),
)
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)
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})
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]
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)
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]
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 %}
{% 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來拖放列表。