読者です 読者をやめる 読者になる 読者になる

Django と South と テーブル名変更

South でテーブル名を変更したい

class Hoge(models.Model):
    text = models.TextField()

hogeアプリケーションにこんなモデルを作るとデータベースのテーブル名はhoge_hogeになります。
Djangoの外に出ないならこのままでも良いんですけど、データベースを直接見たりSQLを書くにはちょっと格好悪いですよね><
そんな時は

class hoge(models.Model):
    text = models.TextField()
    class Meta:
        db_table = 'hoge'

こんな風にdb_tableを指定してあげると、hogeというテーブルになります。
ただし、Southを使っているとこういう変更もmigrationファイルを作る必要があります。

datamigrationを利用して

class Migration(SchemaMigration):
    def forwards(self, orm):
        db.rename_table('hoge_hoge', 'hoge')

    # backwards以下省略

rename_tableを実行するmigrationファイルを作るとテーブル名が変更出来ます。
簡単ですね!


落とし穴あるよー

名前を変えたテーブルが他のテーブルと関連していない場合はこれで大丈夫ですが、関連しているテーブルがあると問題が起こる場合があります。

例えば、hugaアプリケーションにこんなモデルがあるとします。

class Huga(models.Model):
    hoge = models.ForeignKey(Hoge)

そして、settingsのINSTALLED_APPSが

INSTALLED_APPS = (
   'south',

   'hoge',
   'huga'
)

こんな風になってるとエラーが発生する場合があります。

migrationをする時はINSTALLED_APPSの上から順に、そのアプリにある全てのmigrationが実行されるので
1. hogeアプリ:hoge_hoge の create
2. hogeアプリ:hoge_hoge から hoge への rename
3. hugaアプリ:hoge_hoge への ForeignKey を持つ huga の create
となって、hugaにアクセスすると、hoge_hogeなんてテーブルないよ!とエラーが発生するのです。


当たり前な解決策

INSTALLED_APPSの順番をhugaを上にするだけで、この問題は解決します。
migrationの実行順が
1. hugaアプリ:hoge_hoge への ForeignKey を持つ huga の create
2. hogeアプリ:hoge_hoge の create
3. hogeアプリ:hoge_hoge から hoge への rename
となって、hoge_hoge から hoge への rename で、huga の ForeignKey も hoge にちゃんと変更されます。

普通に書いてるとForeignKeyを張られる方を上に書きがちなのですが、普段からForeignKeyを張る方を上に書くようにしてるとこーゆー無駄なのに引っかからずに良いのではないでしょうか。