PythonのMigrationツールSouthのチュートリアルをやった
PythonのMigrationツールSouthのチュートリアルをやったときのメモ書きです
http://ae35.bitbucket.org/south-doc-ja/tutorial/index.html
最初のマイグレーション
マイグレーションファイル作成
python manage.py schemamigration southtut --initial
マイグレーション実行
python manage.py migrate southtut
このようなエラーになる場合はsyncdbを忘れている
django.db.utils.DatabaseError: no such table: south_migrationhistory
最初はsyncdbをしてsouth_migrationhistoryテーブルを作成しておく必要がある
モデルの変更があった場合
./manage.py schemamigration southtut --auto
migrationsパッケージに「add_field_追加したフィールド名.py」のようなファイルが作成される。
確かrailsのmigrationはファイル名を自分で指定しなければいけなかったので、この辺は楽かも。
デフォルト値の指定
モデルにnull=Falseなフィールドを追加している場合、デフォルト値をどうするか聞かれる
? The field 'Knight.shrubberies' does not have a default specified, yet is NOT NULL. ? Since you are adding this field, you MUST specify a default ? value to use for existing rows. Would you like to: ? 1. Quit now, and add a default to the field in models.py ? 2. Specify a one-off value to use for existing columns now
1を選べば何もせずに終了。モデルにデフォルト値の設定を書いて再度実行する場合は1。
2を選ぶと、Pythonプロンプトが表示され、デフォルト値の入力を促される。ここで入力したデフォルト値は既存のレコードにのみ適用されることになる。
既存のフィールドにuniq指定を追加
普通schemamigrationで検知してmigration用のファイルが作成される。
python manage.py schemamigration southtut --auto
ユニーク指定したフィールドが、すでに既存のレコードで重複している場合はどうなるか?
なんか色々エラーになります。まあ当然ですね。
$ ./manage.py migrate southtut
Running migrations for southtut:
- Migrating forwards to 0004_auto__add_unique_knight_name.
> southtut:0004_auto__add_unique_knight_name
FATAL ERROR - The following SQL query failed: CREATE UNIQUE INDEX "southtut_knight_name" ON "southtut_knight"("name");
The error was: indexed columns are not unique
! Error found during real run of migration! Aborting.
! Since you have a database that does not support running
! schema-altering statements in transactions, we have had
! to leave it in an interim state between migrations.
! You *might* be able to recover with:
! The South developers regret this has happened, and would
! like to gently persuade you to consider a slightly
! easier-to-deal-with DBMS (one that supports DDL transactions)
! NOTE: The error which caused the migration to fail is further up.
Error in migration: southtut:0004_auto__add_unique_knight_name自分で重複レコードを修正してmigrateをやり直せばちゃんと通ります
マイグレーションの一覧表示
$ python manage.py migrate --list
データマイグレーション
datamigrationにアプリ名とmigration名(例えばhash_passwords)を指定する
$ python manage.py datamigration southtut2 hash_passwords
datamigrationの場合は作成されたファイルにあるforwards関数に自分で行いたいデータ変更処理を書く
以下はチュートリアルにある例そのままだが、注意点はモデルクラスはormパッケージのものを使うこと。
def forwards(self, orm): import random, sha, string for user in orm.User.objects.all(): user.password_salt = "".join([random.choice(string.letters) for i in range(8)]) user.password_hash = sha.sha(user.password_salt + user.password).hexdigest() user.save()
不可逆な処理の場合はbackwords関数でエラーを発生させる
def backwards(self, orm): raise RuntimeError("Cannot reverse this migration.")
なんとなく感覚はつかめた