Djangoでテーブル名やカラム名の変更( マイグレーション, South ) | 世界的日曜WEBプログラマー日記

世界的日曜WEBプログラマー日記

一年後に世界的なWEBサービスを運営するにはどうすればいいのか書いていく(予定)

Table name, Column nameのリネームなどの方法(Django South)


こんにちわ。宅配弁当専門のWebページを作っているDyanticoの等々力です。

マイ食でもそうだけど、Webサイトを運用しているとデータベースの変更が生じることがよくある。food_itemのテーブルに価格等追加したいなど。

DBの骨格の変更、例えばテーブル名の変更、カラム名の変更や追加、削除。こうした操作をMigration(マイグレーション)とよぶ。(要はDBやテーブルに対する操作)
DjnagoではこのMigration作業をコマンドベースで行う方法が用意されている。

恐らくほとんどのDjangoユーザーはカラム追加のような作業をDBに直接アクセスしておこなっているか、MySQLならワークベンチで次のようにしている。

1. Mysql workbenchでカラムを追加
2. models.pyに当該カラム名を追加

上記の手法に問題はない。ただ、例えば次のような場合に対応できない

お弁当のマイ食のお弁当テーブルに属性を追加!
・全てのテーブル(100個)のカラム名をuid->user_idにしたい(できるが時間がかかる)
・いつカラム名やテーブル名を変更したかをトレースしたい
・サーバーの都合でMysqlを直接叩けない
・プログラムベースでマイグレーションを行いたい!

mysqlコマンドなどでは非常にたるい作業となる!こういう時にはDjangoのMigrationモジュールの出番。
DjangoでテーブルやColumn名の変更、削除などいわゆるMigrationを行うにはSouthモジュールを使う。では早速始めよう。

Django South の 使い方
では早速使ってみる。説明上、まずは恒例のプロジェクトを作成して、アプリを作る。

$ sudo easy_install South # install
$ djnago-admin.py startproject AKB48 # 名前は自由
$ cd AKB48 # プロジェクトへ移動
$ djnago-admin.py startapps itanotomomi # アプリの名前は自由
$ emacs settings.py

作ったアプリitanotomomiとsouthを登録する。

INSTALLED_APPS = (
'django.contrib.auth',
:
'south', # 必ず追加
'itanotomomi', # startappsで追加したもの
)

登録完了後、syncdbをすること # 必ずすること!でないとsouthのテーブルが必要となるため。

$ python manage.py syncdb # syncdb

syncdbを忘れるとdjangoを通じてマイグレーションをした時にdjango.db.utils.DatabaseError: (1146, "Table 'sandbox.south_migrationhistory' doesn't exist")
がでる。逆にコレが出たときは、syncdbをしていない(つまり、テーブルの中にsouthのMigrationヒストリーをほぞンするためのテーブルができていない)

southが正しくインストールできているかどうかについては次のコマンドで確認が出来る。

$ python manage.py shell
> import south

これでエラーが出なければOK!

southを通じたMigrationの方法


DjangoのColumn名の変更など、Southモジュールを用いたマイグレーションの流れとしては
1. models.pyにモデルを定義
2. python mange.py ***migration の実行
3. migrateコマンドの実行
と2ステップとなる。これだけ。これでなんらかの操作(テーブルの作成や変更)が実行される。

自動でmodels.pyに変更した内容を自動で検出し、DBへ変更を促す場合には
$ python manage.py schemamigration
手動で、例えばテーブルやカラム名の変更など行いたい場合は
$ python manage.py datamigration
とする。
どちらともにアプリの場所にmigration fileが生成される。(itanotomomi/migrations)
手動(datamigration)の場合は空ファイルが作成されている。詳細な内容を次。

A. 初期化

A-1.初めてアプリを作る場合(データベースに何もない状態)
python manage.py startappしたてで、何も書かれていないmodels.pyにモデルを定義する。
その後、initial引数でschemamigrationをする。

$ python manage.py schemamigration itanotomomi --initial #migration file 初期化
$ python manage.py migrate itanotomomi

これでmodels.pyに書かれている内容がDBに反映される。

A-2. 途中からアプリを定義
尚、既にMySQLなどのデータベースにテーブルが存在していて、models.pyにもすでにある色々と書かれている程度定義されている場合(ほとんど既にWebを運用している人がそうだと思う), 次を叩く
$ python manage.py convert_to_south itanotomomi
$ python manage.py migrate itanotomomi


B. 二回目以降
上記は--initial、あるいはconvert_to_southの方法は一度だけ。
後は基本的に--autoを用いる。

B-1. 自動で検出して反映する場合
$ python manage.py schemamigration itanotomomi --auto
$ python manage.py migrate itanotomomi

B-2. 手動で定義し、反映する場合

$ python manage.py datamigration itanotomomi cosmetic_surgery
$ python manage.py migrate itanotomomi
$ emacs itanotomomi/migrations/0003_cosmetic_surgery.py # 最初の数字は適当

とする。

マイグレーションファイルはすべてitanotomomiの中のmigrationsに保存されている。


ショートチュートリアル(もともとあるデータベースに定義されていてから行うとき)


1. startapp itatnotomomi # アプリ名はitanotomomi
2. settings.pyに登録( south, itanotomomi ) # easy_install でsouthインストール済と仮定
3. inspectdb --database second # databaseの名前でなくてsettings.pyに書かれていDB
4. syncdb # southはinstalled
5. convert_to_southの実行 # fakeを行う --initializeはしないで!!!!!!
6. migrateの実行 #

tableの作成などはmodels.pyを変更した後、./manage.py schemamigration itanotomomi --autoをするだけで自動的にファイルが創られmigirationsの中にファイルが創られる。
models.pyを変更した後は python manage.py migrateを行うといい。

カラムやテーブル名の変更については手動で行う必要がある。この場合はくどいようだけどschemamigrationではなくdatamigration。

データ編集の流れはschemamigrationの流れと同様に
1. models.pyを編集する。
2. 編集後にdatamigrationを行う。

となる。
datamigrationコマンドを実行することで空のファイルが
<アプリ名>/migrationsフォルダ
に作成される。つまり、上記例だとitanotomomi/migratinosに作成される。

datamigrationの構文は次の通り
$ python manage.py datamigration itanotomomi any_name_you_can_put_here
itanotomomiはアプリ名、その次のはファイル名。コレを実行することで
itanotomomi/migrations/0004_any_name_you_can_put_here.pyが作成される。
( 0004は適当な数字が入る)

カラム名やテーブル名の変更などは自分でファイルを追加しなければならない。
例えばリネームだとdb.rename_column( table_name, old_name, new_name )となる。次は参考例

# -*- coding: utf-8 -*-
from south.db import db
from south.v2 import SchemaMigration

class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting field 'Authmap.uid'
db.rename_column('users_audience', 'uid', 'user_id')

def backwards(self, orm):
# Adding field 'Authmap.uid'
db.rename_column('users_audience', 'user_id', 'uid')

上記はカラムのリネームである。uidをuser_idにしている。

forword, backwordに関しては後ほど説明。書いた後はmigrateを実行することで反映できる。

$ python manage.py migrate itanotomomi


トラブルシューティング
? SouthをEasy_enstallでインストールしたか
? settings.pyに'south’とかいたか
? settings.pyに'itanotomomi’と書いたか
? django.db.utils.DatabaseError: (1146, "Table 'sandbox.south_migrationhistory' doesn't exist")がでたらsyncdbしていないよ。
?mysql_exceptions.OperationalError: (1050, "Table 'ROLLBACK_TEST' already exists")
処理の途中で慌ててCtrl-ccとか押すとこうなってMigrationができなくなる。こういう時はもう胴仕様も無いのでDBをDropするしかない。→嘘。ROLLBACK_TESTというテーブルができているのでこいつをドロップすればいいだけ。


Django Southの説明が長くなった。datamigrationをして解ったことは、schemamigration --autoはitanotomomi/migrationsにmodels.pyをみてテーブルの変更ファイルを生成するためのコマンドというわけだ。

株式会社OctOpt
コンピューターサイエンス会社OctOptの技術公式ブログ
等々力 康弘
@rocky_house