由于我們剛剛完成了很多變更,現在將是一個提交的好時間。你得適應頻繁的提交,要知道,提交的粒度越小,在出錯時回退的自由度越高。
要進行提交操作,讓我們看看都有那些修改。
(git)
1
2
3
4
5
6
7
8
9
10
11
|
$ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) ## modified: django_project/settings.py ## Untracked files: # (use "git add <file>..." to include in what will be committed) ## django_project/.settings.py.swp # django_project/__init__.pyc # django_project/settings.pyc |
(Mercurial)
1
2
3
4
5
|
$ hg status M 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 模式。例如,我的文件內容多半就是:
?
在我們提交之前,還有一個信息需要查看:我們已經安裝的 Python 包。我們希望能夠追蹤使用到的 Python 包的名稱和版本,這樣一來,我們就可以輕松的重建生產環境。pip 正好有個命令可以完成我們這個需求。
1
|
$ pip freeze > requirements.txt |
我將 pip 的輸出存入名為 requirements.txt 的文件,并將這個文件添加到代碼控制中。這樣,我們總是擁有一個更新的列表,里面包含了將使用的包。
現在將 settings.py 及 requirements.txt 添加到提交文件中,并提交:
1
2
|
$ (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:你創建的應用
這可以更容易的看出哪些是你使用的第三方應用,哪些是項目自身的。僅僅記住最后有一行和下面相似的代碼:
1
|
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 <command>,而不需要總是輸入python manage.py <command>。老實說,很少有開發者這么做。我無法搞清楚為什么。
在添加模型前,我們要做的第一件事是我們告訴South我們想用它做遷移:
1
|
$ python manage.py schemamigration myapp --initial |
這將創建一個移植文件,用來應用我們對于數據庫的模型更改(如果我們有的話),而不需要完全銷毀再重建它。當情況偏離時,它也可以讓我們用來 恢復更改。我們使用移植文件來 移植數據庫的變化(即使還沒有變化),命令如下:
1
|
$ python manage.py migrate myapp |
South足夠智能,知道去哪里找到移植文件,也記得我們做的最后的移植。你可以指定單獨的移植文件,但這一般并不是必須的。
當我們最終對模型做出改變時,我們使用下面的命令來讓South創建一個移植文件:
1
|
$ python manage.py schemamigration myapp --auto |
這將檢測myapp中的模型,并自動相應的添加、刪除或修改數據庫中的表。然后使用如上的移植命令就可以將改變應用到數據庫上。
開發區域
還有一件事你需要注意:將開發區域與你已經確認的文件區分開,原因顯而易見。使用Git和Mercurial實現這個很簡單,而且也有助于部署。創建django_project所在目錄之外的一個目錄作為你開發區域(我把它叫做dev)。
在你的開發目錄,使用git或Mercurial克隆當前項目:
1
|
$ (git /hg ) clone /path/to/my/project/ |
兩個工具都將創建庫的一份完整拷貝。所有的更改、分支及歷史都將在新庫中可用。從現在起,你應該在你的開發目錄工作。
由于使用Git和Mercurial來進行分支都容易便捷,當你切換新分支或站點的大規模變化時創建分支。下面是兩個工具的實現方法:
(git)
1
|
$ git checkout -b <branchname> |
這不僅創建了一個命名新分支且會將代碼檢出。幾乎所有的開發工作都應該在分支上,這樣主分支可以隨時恢復。
(Mercurial)
1
|
$ hg branch <branchname> |
請注意,在Mercurial社區里分支是一個有爭議的話題,目前這里有一些可用的選項,但其中還沒有“顯然正確”的。在這里,我使用命名分支,這可能是最安全且最有益的分支風格。任何在branch命令后的提交將在新分支生效。
使用 Fabric 來進行部署
那么我們就有了一個Django應用。我們怎么來部署它呢?Fabric。對一個合理大小的項目來說,討論任何其它的東西都是浪費時間。Fabric可用于許多種不同目的,不過在部署方面它確實很出色。
1
|
$ pip install fabric |
Fabric 需要一個名為fabfile.py的 fabfile 文件,這個文件定義了所有我們可以采用的動作。現在我們就來創建它。將下面這些內容寫入fabfile.py并將其放到項目的根目錄。
1
2
3
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
from fabric.api import lcd, localdef deploy(): with lcd( '/path/to/my/prod/area/' ): # With git... local( 'git pull /my/path/to/dev/area/' ) # With Mercurial... local( 'hg pull /my/path/to/dev/area/' ) local( 'hg update' ) # With both local( 'python manage.py migrate myapp' ) local( 'python manage.py test myapp' ) local( '/my/command/to/restart/webserver' ) |
這將會從開發主分支拉回(pull)變更,運行你實施的任何遷移,運行測試,并且重啟你的web服務器。這些只需在命令行中的一條簡單的命令。如果其中的一條命令失敗了,腳本將會停止運行并報告發生的事情。一旦你修復了這個問題,無需再手工運行其余步驟。因為它們是冪等的,你只需重新運行部署命令,一切都將恢復正常。
(譯注:idempotent 冪等,某一元運算為冪等的時,其作用在任一元素兩次后會和其作用一次的結果相同。)
注意上面的代碼是假設你部署在相同的機器上。如果不是這樣的話,這個文件很可能相同,但是會使用Fabric的run函數來替代local。參見Fabric 文檔 獲取更多細節。
現在我們創建了fabfile.py,該怎樣實際部署呢?很簡單。只需運行:
1
|
$ fab prepare_deployment$ fab deploy |
在技術層面,這些可以合并為一個單獨的命令,但是我覺得最好明確的準備你的部署工作再部署它,因為這樣就使你更關注于你正在做的事情。
建立單元測試
如果你但凡聽說過我,可能就會知道我對自動測試非常著迷。無論如何,有太多的Django項目沒有寫任何測試。這是需要預先花費一點時間去做的事情,但是卻給未來帶來巨大的紅利。如果你曾經使用print語句調試過你的應用,在恰當的地方用合適的測試,這樣就將給你節省許多時間。
對于Django,Python的單元測試模塊完全夠用了。下面是一個app的一個最小的測試例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import datetimefrom django.test import TestCasefrom myapp.models import Postclass BlogPostTestCase(TestCase): def setUp( self ): Post.objects.create( id = 1 , title = 'Starting a Django 1.6 Project the Right Way' , date = datetime.datetime.now(), category = 'Django' ) Post.objects.create( id = 2 , title = 'Python\'s Hardest Problem' , date = datetime.datetime.now(), category = 'Python' ) def test_posts_have_category( self ): """Animals that can speak are correctly identified""" first_post = Post.objects.get( id = 1 ) second_post = Post.objects.get( id = 2 ) self .assertEqual(first_post.category, 'Django' ) self .assertEqual(second_post.category, 'Python' ) |
你可以將這些代碼寫到名為test_<appname>.py的文件中,并將其放到app測試時所在的目錄。為了為app運行這些測試,只需運行./manage.py test <appname>。我們創建的fabfile文件已經知道在部署前運行這些測試,所以不需要再做任何別的修改了。
享受你的新的Django應用程序
就是這些!你已經開始了實際的開發。現在真正的樂趣才會開始。只需記住:經常提交,測試一切,還有不要在你提供服務的地方書寫代碼。無論從現在起會發生什么,你肯定已經以正確的方式開始了一個Django1.6 項目!