最近在著手下一個項目的準備工作,我之前的項目后臺都是用Coldfusion的,Coldfusion的開發速度很快 而且可靠,但是Coldfusion的價格太高了,無形會增加用戶的部署成本,再而,現在做的項目除了后臺部分都是搭建在開源自由的軟件平臺上的,如 MySQL、Linux、Flex等,既然要切換后臺,那更換的方向也是如此,本來想用Java的,可最近我發現自己有點缺少激情了(項目做多了、很多都 在重復,沒什么挑戰性、沒了新鮮感了,所有激情就欠奉了,要不是有五臟六腑需要祭奠,鬼才做這些商業項目呢)。最近社區討論得最多的輕量的快速開發框架就
是ROR和Django,ROR是好,可惜是源于日本鬼子的東西,我這人向來憤青,自然不選了,Django源于Python,Python 有如此豐富的類庫及其廣泛的應用,而且即將迎來里程碑版本Python3000的發布,再加上我Python荒廢多時正想重新拾掇起來,所有就選中了這個 Django作為后臺的框架。至于Flex與Django的通信,我用的PyAmf,之所以選用他,是因為這個支持Flex的RemoteObject。
下面是項目的準備階段手稿,基本來自于各項目的官方文檔。
假定
本文基于Ubuntu Linux,開發環境已經安裝Python、mod_python、subversion、apache、MySQL等環境。相關的安裝大家可以參照各自的官方文檔,這里給出Ubuntu下的安裝方法(Python默認已經安裝不需要安裝):
[bash]
sudo apt-get install apache2 libapache2-mod-python Subversion mysql-server
mysql-client
另外,我們創建一個目錄存放我們項目相關的文件:
[bash]
mkdir -p ~/works/Ananas
后續我們將使用$work_root來指代該目錄。
Django的安裝及相關開發環境的搭建
Django目前才出于開發過程中,其API還在陸續完善中,其實作為實際產品的應用是有風險的,當前的版本是0.96,不過我用的是svn的開發版本,以便官方有更新能夠快速更新。
首先,通過一下命令下載最新的Django代碼(請確保您的系統已經安裝Subversion):
[bash]
cd $work_root
mkdir -p server&& cd server
svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk
接著將Django加載到Python解析路徑中:
[bash]
sudo ln -s $work_root/server/django-trunk/django "
python -c "from distutils.sysconfig import get_python_lib; print
get_python_lib()"`/django
接著將django-admin.py添加到系統路徑中,以便后續使用方便
[bash]
sudo ln -s $work_root/server/django-trunk/django/bin/django-admin.py
/usr/local/bin
以后如果要更新Django,直接使用如下方法更新:
[bash]
cd $work_root/server/django-trunk
svn update
大家可以訪問這里查看安裝過程的官方說明。
創建Django工程
現在我們可以開始創建Django的工程了:
[bash]
mkdir $work_root/server/src&&cd $work_root/server/src
django-admin.py startproject ananas
以上我們首先創建了一個src目錄,該目錄為你的Django工程根目錄,接著創建一個項目ananas,初始的結構如下:
[bash]
ananas/
__init__.py
manage.py
settings.py
urls.py
其中,manage.py是工程管理工具,settings.py則是項目的相關參數設置,而urls.py則是Django的url解析表
接著我們就可以啟動Django 開發服務器了:
[bash]
cd $work_root/server/src/ananas
python manage.py runserver
以上命令會啟用一個Django內置的用python實現的輕量web Server,考慮到我們最終要部署到Apache上,及分布開發的情況,我們這里不使用這個方法,而是使用下面Apache+mod_python的方式。
Django的mod_python配置
首先,激活Apache的mod_python模塊:
[bash]
sudo a2enmod mod_python
接著,修改apache配置文件,在集中添加Django相關的配置:
[bash]
sudo vi /etc/apache2/sites-enabled/000-default
添加在</VirtualHost>前添加如下內容:
[bash]
<Location "/ananas/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE ananas.settings
PythonDebug On
PythonPath "['/path/to/project'] + sys.path"
</Location>
其中,/path/to/project要替換成您的項目根目錄,也就是$work_root/server/src/,在本文中實際的配置應該是:
[bash]
<Location "/ananas/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE ananas.settings
PythonDebug On
PythonPath "['/home/feiy/works/Ananas/server/src'] + sys.path"
</Location>
以上配置表示,對于/ananas的訪問,使用django.core.handlers.modpython來處理,其中的PythonDebug
On,打開調試功能,方便我們開發過程的程序調試,實際生產上需要關閉它。
另外,在末尾添加如下內容:
[bash]
MaxRequestsPerChild 1
該配置強制Apache對于每個請求都重新載入配置,以便我們的Python代碼更新后,不需要重啟Apache。該配置對Apache性能有影響,實際生產上需要刪除它。
接著,啟動apache:
[bash]
sudo /etc/init.d/httpd start
如果您配置正常的話,這時候訪問http://127.0.0.1/ananas/,將會看到如下畫面:
該部分官方的詳細說明可以查看這里
配置Django數據庫訪問
接著我們來配置Django連接MySQL,編輯settings.py文件,修改其中的如下選項:
[python]
DATABASE_ENGINE = '' #
'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = '' # Or path
to database file if using sqlite3.
DATABASE_USER = '' # Not used with sqlite3.
DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_HOST = '' # Set to
empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used
with sqlite3.
文件里面已經說的很清楚了 ,這個分別對應你要使用什么類型數據庫服務器、要連接的數據庫名、用戶名、密碼、數據庫服務器主機地址、端口。分別安裝您的實際數據庫連接情況設置好就可以了。
接著修改INSTALLED_APPS部分:
[python]
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
)
這個部分表示在我們的Django實例中激活了那些應用,一個應用可以用于多個工程,默認的四個應用,分別對應是認證系統、內容識別、session框架和一個但Django對應多個站點的框架。
您可以根據需要添加或刪除應用,比如我們這里不需要認證系統,那么直接將其修改如下:
[python]
INSTALLED_APPS = (
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
)
接著,執行如下命令,為這些應用創建必要的表結構等:
[bash]
python manage.py syncdb
創建我們自己的應用
現在,我們已經搭建好了Django開發環境——創建了一個工程ananas,現在我們來創建我們實際的應用。
使用如下命令創建一個應用:
[bash]
python manage.py startapp users
以上將在當前目錄創建一個users目錄,其內容如下:
[bash]
users/
__init__.py
models.py
views.py
其中,models.py用于定義我們的數據庫模型,將其修改如下:
[python]
from django.db import models
class Department(models.Model):
name =
models.CharField(max_length=80)
def
__unicode__(self):
return
self.name
class User(models.Model):
id=models.CharField(max_length=8,primary_key=True)
name = models.CharField(max_length=40)
dep =
models.ForeignKey(Department)
def
__unicode__(self):
return
self.name
以上定義了兩個表,一個是部門表、一個用戶表,用戶表的dep字段是指向Department的外鍵。關于Django里面model的定義說明請查看這里
接著在settings.py中激活我們的users應用(應用名稱為:ananas.users),將其中的INSTALLED_APPS修改如下:
[python]
INSTALLED_APPS = (
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'ananas.users',
)
返回到工程根目錄,執行以下命令,自動創建表結構:
python manage.py syncdb
以上會自動創建兩個表:users_department和users_users。
初始數據的寫入
現在我們可以利用Django提供的API來方便的寫入我們的一些初始數據。
運行以下命令,進入交互的Python Shell:
[bash]
python manage.py shell
接著輸入如下命令:
[python]
#導入我們前面定義的model類
>>> from ananas.users.models import Department,User
#創建兩個部門
>>> dep1=Department(name='前臺接待部門')
>>> dep1.save()
>>> dep2=Department(name='資信調查部門')
>>> dep2.save()
#驗證是否創建成功
>>> Department.objects.all()
[<Department: 前臺接待部門>, <Department: 資信調查部門>]
#創建三個用戶,分別對應兩個部門
#獲取部門一
>>> dep1=Department.objects.get(name='前臺接待部門')
#當前該部門沒有任何用戶
>>> dep1.user_set.all()
[]
>>> dep1.user_set.create(id='0001',name='feiy')
<User: feiy>
>>> dep1.user_set.create(id='0002',name='feng')
<User: feng>
>>> dep1.user_set.all()
#驗證是否創建成功
[<User: feiy>, <User: feng>]
#獲取部門二
>>> dep2=Department.objects.get(name='資信調查部門')
#當前該部門沒有任何用戶
>>> dep2.user_set.all()
[]
>>> dep2.user_set.create(id='0003',name='eshangrao')
<User: eshangrao>
#驗證是否創建成功
>>> User.objects.all()
[<User: feiy>, <User: eshangrao>, <User: feng>]
怎么樣,Django里面數據訪問很方便吧,更多的Django API信息請查看這里
搭建Flex和Django的橋梁:PyAmf的安裝
以上我們已經準備好了后臺環境,創建了初始的數據,那么我們的Flex程序如何與Django交互呢,答案是PyAmf,這個是Python的Amf實現,通過他,Flex就可以使用Amf的方式和Python程序交互。值得一提的是,這個支持Amf3。
PyAmf目前的穩定版本是0.1,和前面安裝Django一樣的考慮,我們也安裝svn的開發版本
代碼如下
- cd $work_root/server
- svn
co http://svn.pyamf.org/pyamf/trunk pyamf-trunk
- cd pyamf-trunk
- sudo
python setup.py develop
接著在我們的Django工程目錄下創建一個amfgateway.py文件,內容如下:
代碼如下
- from pyamf.remoting.gateway.django import
DjangoGateway
- from ananas.users.models import Department,User
- def getAllDepartments(request):
- return Department.objects.all()
- def getDepAllUsers(request,depID):
-
dep=Department.objects.get(id=depID)
-
return dep.user_set.all()
- def updateUser(request,userID,userName,depID):
-
user=User.objects.get(id=userID)
-
user.name=userName
-
user.depID=depID
- usersGateway = DjangoGateway({
-
'getDepAllUsers': getDepAllUsers,
-
'getAllDepartments':getAllDepartments,
-
'updateUser':updateUser
-
})
以上定義了一個userGateway Amf網關,提供了三個分別獲取所有部門、用戶和更新用戶信息的方法。
接著打開$work_root/server/src/ananas/urls.py,定義AMF網關的訪問URL,用于Flex端訪問。
代碼如下
- from django.conf.urls.defaults import
*
- urlpatterns
= patterns('',
-
Example:
-
(r'^ananas/',
include('ananas.foo.urls')),
-
-
Uncomment this for
admin:
-
(r'^admin/',
include('django.contrib.admin.urls')),
-
(r'^ananas/gateway/',
'ananas.amfgateway.usersGateway'),
- )
以上定義對/ananas/gateway的訪問,使用usersGateway進行處理。(注意,這個urls.py是Django里面的最經典的東西,這樣可以使用正則表達式,定義非常靈活的URL處理)
接著我們來進行Flex端的開發。
首先,為了代碼分離的考慮,我們將后臺Django服務配置的設置單獨存放在services-config.xml文件里面:
代碼如下
- <?xmlversion="1.0"encoding="UTF-8"?>
- <services-config>
- <services>
- <serviceid="ananasService"class="flex.messaging.services.RemotingService"messageTypes="flex.messaging.messages.RemotingMessage">
- <destinationid="ananasAmf">
-
<channels>
-
<channelref="ananasChannel"/>
-
</channels>
-
<properties>
-
<source>*</source>
-
</properties>
-
</destination>
-
</service>
-
</services>
-
<channels>
-
<channel-definitionid="ananasChannel"class="mx.messaging.channels.AMFChannel">
-
<endpointuri="http://127.0.0.1/ananas/gateway/"class="flex.messaging.endpoints.AMFEndpoint"/>
-
</channel-definition>
-
</channels>
-
</services-config>
注意,其中<endpoint />里面的uri地址就是我們前面在Django的urls.py中定義的PyAMF網關訪問URL地址一致。
下面是一個簡單的Flex的測試代碼:
代碼如下
- <?xml version="1.0" encoding="utf-8"?>
- <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="getAllDepartment()">
-
<mx:Script>
- <![CDATA[
- import
mx.rpc.AsyncToken;
- import
mx.rpc.AsyncResponder;
- import
mx.rpc.events.FaultEvent;
- import
mx.rpc.events.ResultEvent;
- import
mx.controls.Alert;
-
- private
function getAllDepartment():void{
-
var token:AsyncToken=djangoService.getAllDepartments();
-
token.addResponder(new AsyncResponder(AfterGetDeps,falutHandler));
- }
- [Bindable]
- private var
depAC:Array;
- private
function AfterGetDeps(result:Object, token:Object=null):void{
-
var evt:ResultEvent=result as ResultEvent;
-
depAC=evt.result as Array;
- }
- private
function falutHandler(error:Object, token:Object=null):void{
-
var evt:FaultEvent=error as FaultEvent;
-
Alert.show(evt.message.toString());
- }
-
- [Bindable]
- private var
userAC:Array;
- private
function doQueryUser():void{
-
var
token:AsyncToken=djangoService.getDepAllUsers(dep_cb.selectedItem.id);
-
token.addResponder(new AsyncResponder(AfterGetUsers,falutHandler));
- }
- private
function AfterGetUsers(result:Object, token:Object=null):void{
-
var evt:ResultEvent=result as ResultEvent;
-
userAC=evt.result as Array;
- }
- ]]>
- </mx:Script>
-
<mx:RemoteObject
- id="djangoService"
- destination="ananasAmf"
- showBusyCursor="true"/>
-
<mx:Panel title="用戶管理">
-
<mx:DataGrid dataProvider="{userAC}">
-
<mx:columns>
-
<mx:DataGridColumn dataField="id" headerText="員工號" width="100"/>
-
<mx:DataGridColumn dataField="name" headerText="姓名" width="200"/>
-
</mx:columns>
-
</mx:DataGrid>
-
<mx:ControlBar>
-
<mx:ComboBox id="dep_cb" dataProvider="{depAC}" labelField="name"/>
-
<mx:Button label="查詢" click="doQueryUser()"/>
-
</mx:ControlBar>
-
</mx:Panel>
- </mx:Application>
注意其中,<RemoteObject/>的destination=”ananasAmf”與我們前面的services-config.xml中定義的<destination id=”ananasAmf”>一致。
注意編譯以上程序的時候,請使用“-services services-config.xml”參數加載Service配置。