1. 程式人生 > >Django: 初始化資料及安裝時程式碼

Django: 初始化資料及安裝時程式碼

PS:The B-List是個很牛的Django部落格,大量的技巧和教程,英語好的一定要去訂閱,怕看英語的,就等我的翻譯吧。

經常被問到的一個問題是:我怎麼樣為我的app提供初始化資料?或者一個相似的問題:我怎麼樣保證我的程式在通過syncdb安裝的同時執行某些程式碼。Django提供了多種途徑實現這個功能,你可以根據具體的需求選擇不同的實現方式。雖然這些功能在文件裡都已經說明了,但是還是會遇到很多問題,所以我們今天仔細看看各種不同的方式之間的區別,瞭解哪一種更適合你。

提供SQL語句初始化資料

這是最古老的方式(從Django一開始就有這個功能)也是最簡單的方式(不管是你需要做的部分,還是它所支援的功能)來為你的Application提供一些初始化資料:你只需要提供一個SQL檔案,包含標準的Insert語句,Django會在建立了資料表以後執行你的SQL檔案。

要使用該方式,你需要在你的app目錄下增加一個"sql"目錄,對應你的每個model所需要的初始化資料,提供一個"model名.sql"的檔案,model名是跟你定義的model相同的名字(這裡使用小寫,也就是get_model()方法返回的名字或者在model的meta資訊中定義的model名字)。比如,我有一個名為blog的application,其中包含一個Entry的model,那我就可以在blog裡面的sql目錄下放一個entry.sql檔案,裡面寫insert語句就可以了。

在這個檔案裡你也可以放其它的SQL語句,不僅僅是INSERT,但是需要提醒你,同一個app的多個SQL初始化檔案,其執行順序是不一定的,而且也不是所有的SQL語法都支援。為了處理不同的資料庫型別的SQL相容性,Django會對該檔案進行處理,而不是直接去執行它。

你可以使用manage.py的sqlcustom命令檢視一個app是否提供了初始化SQL。


使用fixtures

Fixtures是一種新的提供初始化資料的方法,並且被Django的測試框架用來處理單元測試的測試資料。不同於SQL檔案的是,使用fixture你可以提供一個被Django的serialization系統所能識別的序列化檔案,它會被讀取並自動轉換成對應的model,然後儲存進你的資料庫。

你需要建立一個fixture檔案(使用manage.py的dumpdata命令更簡單),確保檔名為"initial_data",字尾名可以是json, xml, yaml, python其一。

把這個檔案放到你的app目錄下的fixtures目錄裡,它就會在執行syncdb的時候建立完你的資料表後自動讀取並插入資料。

如果你有更多fixtures檔案或者你沒有在執行syncdb的時候提供fixture的話,你也可以使用manage.py的loaddata命令手工載入fixture。

使用post_syncdb訊號

第三種,最複雜最強大的方法,是使用Django內部分發器提供的post_syncdb訊號。你可能還不瞭解這個東西,分發器是一種方法,Django的許多程式,包括你自己的程式,可以用它來通知部分某個事件,只需要傳送一個訊號。post_syncdb是個Django內建的訊號,當一個app的資料表被使用syncdb建立時被髮送。

要使用這種方法,你需要在你的app目錄下建立一個名為management.py的檔案,新增下面的程式碼:
from django.dispatch import dispatcher
from django.db.models.signals import post_syncdb
from myapp import models as myapp
用你自己的app的名字替換最後一行的內容。比如我有一個app名為blog,那麼這一行應該是這樣:
from blog import models as blog_app

然後定義一個普通的Python函式,裡面是你希望在安裝時被執行的程式碼。一旦該函式被註冊到分發器上(一會就能看到了),它就會在syncdb建立完資料庫以後立刻被執行,所以這個函式可以實現你想要的任何功能,包括修改資料表,新增額外功能,或者使用Django的model API插入資料。

最後,把你的函式註冊到分發器,使它監聽post_syncdb訊號。dispatcher.connect()方法包括三個引數:
1、你的函式名,必須是一個函式,而不是一個字串
2、訊號的名字,這裡是post_syncdb
3、傳送者,這裡應該是你前面匯入的那個app

繼續blog的例子,你可以定義一個函式setup_blog(),並像這樣來註冊它:
dispatcher.connect(setup_blog, signal=post_syncdb, sender=blog_app)

執行syncdb時,Django會在你的app目錄尋找management.py檔案並匯入,此時dispatcher.connect被執行並註冊你的函式,當你的表被建立後,post_syncdb訊號會發給你的application,分發器會確保你的函式會被呼叫。

Django的認證應用使用了這種方法來自動建立超級管理員,sites應用使用這種方法建立預設的站點。

如果你希望你的程式在任何其它的app被安裝時做些什麼,你可以忽略傳送者引數,那麼每次syncdb被呼叫安裝了一個程式的時候你的程式碼都會被執行。如果你打算這麼做,那麼你需要確保你的函式接收另外的幾個可選引數(分發器會正確的傳遞它們):
app引數,可以傳遞給get_models()以便取得剛剛被安裝的app裡面的model
created_models,是一個list,包含了剛剛實際被建立了表的model

有幾個Django內建的應用使用了這個技巧:
認證應用在每個model被安裝時為它們建立Permission物件
contenttypes框架在每個model被安裝時為它們建立ContentType物件

隨機應變

通常,這幾種技術在不同的場合可以工作的很好,所以,挑選一個最適合你的:

如果你需要提供一些初始化資料,還有一些額外的SQL(比如建立觸發器),並且你知道你的app會被安裝在哪種資料庫上,那就使用SQL檔案。如果需要插入的資料量很大,那麼這也是個好方法,因為避免了不停的建立model物件的開銷。
Fixtures適用於少量的初始化資料,因為它使用Django的序列化功能,所以不依賴於特定的資料庫。它執行起來沒有SQL快,因為要建立物件。另外,這個功能可以在你切換資料庫平臺的時候使用,比如我要把系統從Mysql切換到PostgreSQL,就可以使用fixtures來匯入轉出資料。
post_syncdb方式給你提供了最大的自由來執行任何的Python程式碼,但是寫起來有點煩。所以適用於只用來建立單個的物件,比如超級管理員。或者你需要在每個應用被安裝後做點什麼。