星期三, 1月 24, 2007

[tip] 透過django ORM轉換資料庫資料

之前剛好案子無預警的突然得從開發時採用的sqlite3轉成上線使用的postgresql,
那還好django的ORM是資料庫中立的, 不至於產生太大問題.
首先第一步當然是改settings.py之後syncdb把postgresql資料庫重新建立起來.
但是這樣一來舊有的資料就不見了.
要怎麼把舊的資料從sqlite3的資料庫轉到postgresql呢?

非到最後關頭請先不要急著寫SQL,
透過django的ORM轉換資料庫的舊資料其實簡單的多.
先將sqlite的資料透過cPickle作python object的serialization,
(文謅謅的, 其實就是把sqlite裡的資料存到硬碟成為python物件)
再透過新的設定值將物件讀回來,再存到postgresql裡.

一個重點是要記得QuerySet是Lazy evaluate的,
所以要加那個list()強迫evalutate, 否則資料會沒有真的存進去.

以下是我轉換的兩個範例script:
tran1.py:

from django.conf import settings
settings.configure(
DATABASE_ENGINE = 'sqlite3',
DATABASE_NAME = 'data.db'
)
from XXX.models import MMM

objs = list(MMM.objects.all ())
import cPickle
output = open('data.pkl', 'wb')
cPickle.dump(objs, output)
output.close()

tran2.py:

#!/usr/bin/python
from django.conf import settings
settings.configure (
DATABASE_ENGINE = 'postgresql',  
DATABASE_NAME = 'pserver',  
DATABASE_USER = 'django',
DATABASE_PASSWORD = 'abc',
DATABASE_HOST = 'localhost',
DATABASE_PORT = '5432'
)

from XXX.models import MMM
import cPickle
pkl_file = open('data.pkl', 'rb')
data1 = cPickle.load(pkl_file)
pkl_file.close()

[x.save() for x in data1 ]

我只轉換了一個table, 多個tables也只要如法泡製即可.
可能還有更簡單的方法, 不過對於我而言這樣就很夠了.

簡單擴充一下這個方法,
應該也可以套用在某些資料庫需要變更schema的情形而毋需撰寫SQL,
如果等不到django schema evolution的branch發展起來,
可以自己動手寫看看.

沒有留言: