項目開始時是一個關鍵時刻,選擇會對項目產生長期的影響。有很多關於如何開始使用Django架構的教程,但很少討論如何專業地使用Django,或如何使用行業公認的最佳做法來確保你的項目規模的持續增長。事前的籌劃讓你(和所有同事的生活)在走向將來時更容易。
文章結束時,你將有
- 一個全功能的Django 1.6項目
- 原始碼受控的所有資源(使用Git或Mercurial)
- 自動迴歸和單元測試(使用unittest庫)
- 一個獨立於特定環境的安裝項目(使用virtualenv)
- 自動化的部署和測試(使用Fabric)
- 自動資料庫遷移 (使用South)
- 一個標度你網站的開發工作流程
除第一部在官方教程中外其他部分教程裡都沒有。它們應該這樣。如果你想開始一個新的、生產就緒的Django 1.6項目,請繼續往下看。
先決條件
假定你已瞭解Python的基本知識,同時,以往的一些Django經驗會有協助,但這不是必要的。你需要git或Mercurial來進資料列版本設定。就這些!
準備安裝
我假設你已經安裝了Python。如果你沒有的話到python.org找到與你系統架構相符的版本下載安裝。我使用一個Linode上的64位的Ubuntu伺服器,我很高興使用Linode的服務。
那麼,第一步是什麼呢?安裝Django?不完全是。將安裝包直接安裝到你當前的site-packages裡有一個常見的問題:如果你的機器上有一個以上的Python項目使用Django等其他庫,你可能會碰到應用和安裝軟體庫之間依賴性的問題。因此,我們將使用virtualenv和它的延展virtualenvwrapper來管理我們的Django安裝。這是Python和Django使用者的實踐建議。
如果你使用pip來安裝第三方庫(我不明白你為什麼不),你可以通過簡單的操作安裝virtualenv和virtualenvwrapper。
$ pip install virtualenvwrapper
安裝完後,將下附內容添加到你的shell啟動設定檔中(.zshrc、.bashrc、.profile等)
代碼如下:
export WORKON_HOME=$HOME/.virtualenvsexport PROJECT_HOME=$HOME/directory-you-do-development-insource /usr/local/bin/virtualenvwrapper.sh
重載一下你的啟動設定檔(source .zshrc),現在你已經就緒了。
建立一個新環境
建立一個虛擬環境很簡單,只需輸入
$ mkvirtualenv django_project
“django_project”是你的項目的命名。
你會注意到立馬發生的一些事情:
你的shell前面加上了“(django_project)”
distribute和pip被自動安裝了
這裡是virtualenvwrapper的一個很有用的部分:它會自動為你準備好環境,讓你馬上可以使用pip安裝庫。“(django_project)”的部分是提醒你正在使用的是virtualenv而不是你系統上的Python。要退出虛擬環境只需簡單輸入deactivate即可。當你要回到你的項目開始工作時,只需使用workon django_project即可。需要注意的是這與vanilla virtualenv工具不同,在哪裡運行這些命令都可以。
安裝Django
“等一下,‘安裝Django'?我已經安裝Django了!”,太好了。不過你不會用它的。相反,我們將使用機器上的一個被virtualenv管理的且不會被其他使用者(或你自己)弄亂的Django安裝。在virtualenv中安裝Django,只需輸入:
$ pip install django
這樣最新版的Django將被安裝在你的virtualenv環境裡,你可以這樣確認:
$ which django-admin.py
這會指出你的$HOME/.virtualenvs/目錄。如果沒有的話,確認你的輸入提示裡有“(django_project)”。如果沒有,使用workon django_project啟用virtualenv。
建立項目
在我們真正開始這個項目之前,我們先來談一談。我在過去的幾年裡諮詢過很多Django/Python項目並且和許多開發人員討論過。一個具有壓倒性的事實是,那些具有最多困難的事情往往都沒有使用任何的版本控制。這聽起來讓人難以置信(想想GitHub的流行程度吧),但是開發人員們根本不會去接觸版本控制。也有一些人認為"這是個小項目",沒有必要使用版本控制。這是錯誤的。
這裡列出的工具不會讓你為了使用版本控制而增加更多額外的支出。
之前,我只提到過git作為(D)VCS。但是,既然這個項目是Python寫的,Mercurial也是一個基於Python的不錯的選擇。因為兩者都比較流行,所以你能找到許多線上學習資源。確保你已經安裝了git或者Mercurial。兩者都可以通過你的distro's packaging系統擷取它們。
如果你打算用git,GitHub顯然是一個很好的選擇可以把你的代碼儲存到遠程倉庫裡。使用Mercurial的話, Atlassian的Bitbucket是一個不錯的選擇(它也支援git,所以你用git或者Mercurial都行)
(源碼)控制你的環境
即使我們還沒真正做什麼,但我們知道我們想讓所有東西都在源碼控制下。我們有兩類“東西”將提交:你的代碼本身(包括模板,等等)和支援檔案,像資料庫夾具、South遷移(以後會更多)和requirements.txt檔案,列出你的項目依賴的所有包,允許自動構建環境(不需要再次使用pip install安裝所有包)。
讓我們開始建立我們的專案檔夾。使用django-admin.py提供的startproject命令來設定。
$ django-admin.py startproject django_project
我們將看到建立了一個單獨的檔案夾:django_project。在django_project檔案夾內,我們將看到 另一個包含了常見元素的django_project檔案夾:setting.py,urls.py和wsgi.py。在第二個django_project檔案夾的同一級內有manage.py檔案。
插曲:項目vs.應用程式
你也許會好奇,在Django1.4中,為什麼已經有了建立應用程式的命令還要增加建立項目的命令。答案在於Django“項目”和Django“應用程式”的區別。簡單來說,一個項目是一套完整的網站或者應用。一個“應用程式”是一個可以用在任何Django項目中的很小的、(希望是)獨立的Django應用。如果你正在構建一個叫做“超級部落格”的部落格應用,那麼“超級部落格”就是你的Django項目。如果“超級部落格”支援讀者投票,那“投票”就是被“超級部落格“使用的一個Django應用程式。這個概念就是需要你的投票應用程式可以應用在其他需要使用者投票的Django項目中,而不是僅能應用在”超級部落格“項目中。一個項目就是一堆應用程式按照項目特定的邏輯構建的一個集合。一個應用程式可以應用在多重專案中。
儘管你會本能地傾向於在你的“投票”應用程式中包含大量"超級部落格"的特定代碼和資訊,但避免這樣有許多好處。基於松耦合的原理,將你的應用編寫為一個獨立的實體可以保持設計意圖,並且可以避免項目裡的bug直接影響到你的應用。這也意味著,如果你希望的話,你可以把你的任何應用程式發給另一個開發人員,且他們不需要訪問或更改你的主專案。
像軟體開發中的許多事情一樣,這需要一點付出,但回報很豐厚。
建立倉庫
現在我們的項目裡已經有一些“代碼”了(確實來說只是一些股票指令碼和空的設定檔,恕我這樣說),現在是我們初始我們源碼控制庫再好不過的時間了。下面是在Git和Mercurial中實現的步驟。
git
$ git init
這條命令在目前的目錄建立了一個git倉庫。將我們所有的檔案添加到git以便提交。
$ git add django_project
現在,我們將代碼切實提交到我們的新庫中:
$ git commit -m 'Initial commit of django_project'
Mercurial
$ hg init
這條命令在目前的目錄建立了一個Mercurial倉庫。將我們所有的檔案添加到git以便提交。
$ hg add django_project
現在,我們將代碼切實提交到我們的新庫中:
$ hg commit -m 'Initial commit of django_project'
如果你打算使用像GitHub或者Bitbucket,現在是時候把代碼push上去了。
使用South進行資料庫遷移
Django中最令人沮喪的特性之一是管理模型的變化和資料庫的相關變化。有了South的協助,你可以實現建立一個完整的應用,而不需要寫具體的資料庫代碼。South會建立一個遷移檔案來檢測你的模型變化,並自動在資料庫中產生。這使得你既可以前向根據最新變化來遷移資料庫,又可以後向取消一個變化或者一系列變化。它讓你的生活如此簡單,Django發行版沒有包含它真讓人吃驚。
何時開始使用South
在前面的文章中,我建議在項目的一開始就使用South。對於相對簡單的項目而已,這挺好。然而,如果在你的原型中有大量的模型有很大的變化,那現在不是使用South的時候。對應的,僅僅丟掉並在需要時重建資料庫。你可以編寫指令碼來構成擁有一些測試資料的資料庫,並在需要時編輯它們。然而,一旦你的模型不再變化,儘快開始使用South。這很簡單:
./manage.py convert_to_south
安裝和設定
仍然在我們的虛擬環境下,像這樣安裝South:
$ pip install south
我們在項目的settings.py檔案中把South添加到INSTALLED_APS中。現在就添加,包括你的項目中的資料庫設定,然後運行python manage.py syncdb。你將需要提升許可權使用超級使用者名稱和密碼(你可以輸入然後斷行符號)。更重要的是,South已經在資料庫中設定好了它需要用的表格。
你可能認識到我們並沒有在項目中添加應用,而只是運行了 syncdb。先這樣做可以讓 South 在一開始的時候就被安裝。使用 South,在我們應用中的所有遷移工作都可以完成,包括初始遷移。
由於我們剛剛完成了很多變更,現在將是一個提交的好時間。你得適應頻繁的提交,要知道,提交的粒度越小,在出錯時回退的自由度越高。
要進行提交操作,讓我們看看都有那些修改。
(git)
$ git status# On branch master# Changes not staged for commit:# (use "git add ..." to update what will be committed)# (use "git checkout -- ..." to discard changes in working directory)## modified: django_project/settings.py## Untracked files:# (use "git add ..." to include in what will be committed)## django_project/.settings.py.swp# django_project/__init__.pyc# django_project/settings.pyc
(Mercurial)
$ hg statusM django_project/django_project/settings.py? django_project/django_project/.settings.py.swp? django_project/django_project/__init__.pyc? django_project/django_project/settings.pyc
使用 git 和 Mercurial,你可能發現一些你永遠都不希望提交的檔案,例如上面出現的 python 編譯 後的 .pyc 檔案,以及 vim 的.swp 分頁檔。要忽略這些檔案,在項目的根目錄中建立一個 .gitignore 或 .hgignore 檔案,並在其中添加匹配你不希望追蹤的檔案的 shell 模式。例如,我的檔案內容多半就是:
?
代碼如下:
*.pyc.*swp
在我們提交之前,還有一個資訊需要查看:我們已經安裝的 Python 包。我們希望能夠追蹤使用到的 Python 包的名稱和版本,這樣一來,我們就可以輕鬆的重建生產環境。pip 正好有個命令可以完成我們這個需求。
$ pip freeze > requirements.txt
我將 pip 的輸出存入名為 requirements.txt 的檔案,並將這個檔案添加到代碼控制中。這樣,我們總是擁有一個更新的列表,裡麵包含了將使用的包。
現在將 settings.py 及 requirements.txt 添加到提交檔案中,並提交:
$ (git/hg) add django_project/settings.py requirements.txt$ (git/hg) commit -m 'Added South for database migrations'
新型設定
隨著開發人員對Django和Python越來越舒適,他們會發覺settings.py就是個簡單的Python指令碼,因此可以“編寫”。對settings.py的一個常見方式是從一個頗為古怪的專案檔夾移動到一個新的叫做conf或者config的檔案夾。要清楚你需要對manage.py做些小改變來適應這個移動。
在setting.py內,INSTALLED_APPS會很快變成一堆第三方的包,自身django應用和項目特定的應用。我習慣把INSTALLED_APPS分成三個類別:
- DEFAULT_APPS:作為預設Django安裝(像admin)的一部分的Django架構應用
- THIRD_PARTY_APPS:像South
- LOCAL_APPS:你建立的應用
這可以更容易的看出哪些是你使用的第三方應用,哪些是項目自身的。僅僅記住最後有一行和下面相似的代碼:
INSTALLED_APPS = DEFAULT_APPS + THIRD_PARTY_APPS + LOCAL_APPS
否則,Django將會出現沒有定義INSTALLED_APPS的錯誤。
建立我們的應用
以正常的方式使用manage.py來建立一個應用(python manage.py startapp myapp),並把它加入到INSTALLED_APP中。同時,花費時間讓manage.py可執行(chmod +x manage.py),這樣你就可以僅僅輸入./manage.py ,而不需要總是輸入python manage.py 。老實說,很少有開發人員這麼做。我無法搞清楚為什麼。
在添加模型前,我們要做的第一件事是我們告訴South我們想用它做遷移:
$ python manage.py schemamigration myapp --initial
這將建立一個移植檔案,用來應用我們對於資料庫的模型更改(如果我們有的話),而不需要完全銷毀再重建它。當情況偏離時,它也可以讓我們用來 恢複更改。我們使用移植檔案來 移植資料庫的變化(即使還沒有變化),命令如下:
$ python manage.py migrate myapp
South足夠智能,知道去哪裡找到移植檔案,也記得我們做的最後的移植。你可以指定單獨的移植檔案,但這一般並不是必須的。
當我們最終對模型做出改變時,我們使用下面的命令來讓South建立一個移植檔案:
$ python manage.py schemamigration myapp --auto
這將檢測myapp中的模型,並自動相應的添加、刪除或修改資料庫中的表。然後使用如上的移植命令就可以將改變應用到資料庫上。
開發地區
還有一件事你需要注意:將開發地區與你已經確認的檔案區分開,原因顯而易見。使用Git和Mercurial實現這個很簡單,而且也有助於部署。建立django_project所在目錄之外的一個目錄作為你開發地區(我把它叫做dev)。
在你的開發目錄,使用git或Mercurial複製當前項目:
$ (git/hg) clone /path/to/my/project/
兩個工具都將建立庫的一份完整拷貝。所有的更改、分支及曆史都將在新庫中可用。從現在起,你應該在你的開發目錄工作。
由於使用Git和Mercurial來進行分支都容易便捷,當你切換新分支或網站的大規模變化時建立分支。下面是兩個工具的實現方法:
(git)
$ git checkout -b
這不僅建立了一個命名新分支且會將代碼檢出。幾乎所有的開發工作都應該在分支上,這樣主分支可以隨時恢複。
(Mercurial)
$ hg branch
請注意,在Mercurial社區裡分支是一個有爭議的話題,目前這裡有一些可用的選項,但其中還沒有“顯然正確”的。在這裡,我使用命名分支,這可能是最安全且最有益的分支風格。任何在branch命令後的提交將在新分支生效。
使用 Fabric 來進行部署
那麼我們就有了一個Django應用。我們怎麼來部署它呢?Fabric。對一個合理大小的項目來說,討論任何其它的東西都是浪費時間。Fabric可用於許多種不同目的,不過在部署方面它確實很出色。
$ pip install fabric
Fabric 需要一個名為fabfile.py的 fabfile 檔案,這個檔案定義了所有我們可以採用的動作。現在我們就來建立它。將下面這些內容寫入fabfile.py並將其放到項目的根目錄。
from fabric.api import localdef prepare_deployment(branch_name): local('python manage.py test django_project') local('git add -p && git commit') # or local('hg add && hg commit')
這樣就會運行這個測試並提交你的變更,但是提交只在測試通過的條件下發生。在此處,生產環境中一個簡單的"pull"動作都可以成為實際部署。我們給實際部署再增加一些東西。將以下內容增加到fabfile.py: