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.")
なんとなく感覚はつかめた