高見龍

iOS app/Ruby/Rails Developer & Instructor, 喜愛非主流的新玩具 :)

在Django裡做Database Migration

在Django新增Model是很容易的,只要建立一個繼承自models.Model的類別就行了。但比較麻煩的問題是,如果在syncdb之後還需要調整欄位的話,即使在修改Model屬性再做一次syncdb,會發現Django對於已經sync過的Model會忽略掉。所以如果在syncdb之後要再新增/修改/刪除欄位的話,大致上有兩種做法:

  1. 砍掉重練,砍掉之後再重新syncdb。
  2. 手動修改資料庫的欄位以符合Model的屬性。

如果在開發初期,第一種做法還滿簡單的。但萬一已經是在線上運作的系統就不能用這種方式;第二種做法雖然可行,但每次都得手動改,其實也滿麻煩的。

這時候,如果可以有資料庫的Migration功能就很方便了。為什麼資料庫需要做Migration? 直接修改資料庫欄位有什麼不好? 一來手工修改麻煩,二來如果同時有多人一起開發的時候,你手動修改了資料庫欄位,可能會造成別人寫的程式出現錯誤。最大的好處是,有了DB Migration,資料庫也可以做版本控制了。

在Ruby on Rails有內建的DB Migration的機制,在Django並沒有,不過可以透過另外的模組:south,來完成這個功能。

安裝

如果你有apt-get可以用:

> apt-get install python-django-south

或是使用easy_install來安裝:

> easy_install South

或是到這裡,直接下載整個壓縮檔,解壓縮之後進到該目錄裡,執行:

> python setup.py install


請注意,使用apt-get或是easy_install可能都會需要root權限!


安裝完成之後,請把south加入到專案的INSTALLED_APPS裡:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    # Uncomment the next line to enable the admin:
    'django.contrib.admin',
    # Uncomment the next line to enable admin documentation:
    # 'django.contrib.admindocs',
    'author',
    'south',
)

再來請執行一次syncdb,Django會幫你產生一個資料表south_migrationhistory,用來紀錄Migration的歷史紀錄:

> python manage.py syncdb
Syncing...
Creating tables ...
Creating table south_migrationhistory
Installing custom SQL ...
Installing indexes ...
No fixtures found.

Synced:
 > django.contrib.auth
 > django.contrib.contenttypes
 > django.contrib.sessions
 > django.contrib.sites
 > django.contrib.messages
 > django.contrib.staticfiles
 > django.contrib.admin
 > author
 > south

Not synced (use migrations):

使用

如果要把之前建好的author這個app加進Migration裡:

> python manage.py convert_to_south author

然後你會發現在author資料夾裡面多了一個叫做migrations的目錄,裡面放了一個0001_initial.py

接下來,當你在Model做任何欄位修改之後,只要執行這行:

> python manage.py schemamigration author add_mobile_column --auto

它就會幫你找出你做了哪些欄位上的修改。如果你的欄位沒有指定預設值並且不允許NULL的話,過程中south會問你一些問題,請你指定預設值給它。順利的話,它應該會在migrations資料夾底下產生一個0002_add_mobile_column.py

但做到這裡並還沒有正式的修改到資料庫,接下來請執行python manage.py migrate

> python manage.py migrate
Running migrations for author:
 - Migrating forwards to 0002_add_mobile_column.
 > author:0002_add_mobile_column
 - Loading initial data for author.
No fixtures found.

這樣就會把剛剛做的異動正式寫入資料庫了。

回復

前面提到,資料庫有做Migration最大的好處就是隨時可以回到某一個版本,例如我們想要回到最一開始的版本的話:

> python manage.py migrate author 0001
 - Soft matched migration 0001 to 0001_initial.
Running migrations for author:
 - Migrating backwards to just after 0001_initial.
 < author:0003_change_table_name
 < author:0002_add_mobile_column

這樣就搞定了,跟手動修改資料欄位比較起來,方便許多。

Comments