Django on HerokuだとSouthが便利

先日のHextrisではHerokuでDjangoを動かしています。色々便利で良い具合なんですけど、1つ困った事がありました。無料プランだとShared Databaseという事で共有のPostgreSQLを割り当てられるのですが、psqlなどで直接アクセスできません。

またDjangoのsyncdbコマンドは、Modelを変更した際にスキーマ変更を行ってくれません。Railsのscaffold等はスキーマ変更に対応しているのでオプション等が用意されてても良いのにと思います。

なのでpsqlで直接ALTER TABLEもできないしどうしたら良いんだ!となっていたのですが、調べてみるとSouthというモジュールを使えば、manage.pyにスキーマ変更用のコマンドを追加される事が解りました。使い方をざっくりメモしておきます。

準備
インストールはpip/easy_installで一発です。なおSouthはDjangoのアプリケーションです。

$ pip install South

インストールできたらDjangoのsettings.pyにSouthを設定します。

INSTALLED_APPS = (
    ...
    'south'
)

settings.pyにSouthを設定したら一度syncdbを走らせます。South自体のModelをデータベースに反映させる為です。

マイグレーション
Southはある時点のModelのスキーマを保存しておいて、修正が行われた場合はその差分を検出してALTER TABLE等のコマンドを発行してくれます。なのでModelの変更を行う前に現時点の情報を保存しておく必要があります。この為に最初の1回のみconvert_to_southというコマンドを使います。

$ python manage.py convert_to_south myapp

convert_to_southを実行したらModelに必要な変更を行います。Modelを変更したら早速southを使ってスキーマに適用してみましょう。ここではBookというモデルにisbnというカラムを追加してみました。

$ python manage.py schemamigration myapp --auto
 + Added field isbn on myapp.Book
Created 0002_auto__add_field_book_isbn.py. You can now apply this migration with: ./manage.py migrate myapp
$ python manage.py migrate myapp
Running migrations for myapp:
 - Migrating forwards to 0002_auto__add_field_book_isbn.
 > myapp:0002_auto__add_field_book_isbn
 - Loading initial data for myapp.
No fixtures found.

schemamigrationコマンドで、マイグレーション用のデータを作成し、migrateコマンドでマイグレーションを実行します。以上でModelの変更をスキーマに反映させられます。

ちなみにschemamigrationコマンドで生成された0002_auto__add_field_book_isbn.pyの内容は以下のようになっています。forwardの中でadd_columnが呼ばれていますね。

# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models

class Migration(SchemaMigration):

    def forwards(self, orm):
        
        # Adding field 'Book.isbn'
        db.add_column('myapp_book', 'isbn', self.gf('django.db.models.fields.TextField')(default=''), keep_default=False)


    def backwards(self, orm):
        
        # Deleting field 'Book.isbn'
        db.delete_column('myapp_book', 'isbn')


    models = {
        'myapp.book': {
            'Meta': {'object_name': 'Book'},
            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
            'isbn': ('django.db.models.fields.TextField', [], {'default': "''"}),
            'price': ('django.db.models.fields.IntegerField', [], {}),
            'title': ('django.db.models.fields.TextField', [], {})
        }
    }

    complete_apps = ['myapp']

これでherokuの無料プランでDjango使う時も特にスキーマ変更を気にせず、勢いでプロトタイプが作っていけますね。というかherokuに限らずDjango使うときは普通に便利です。他にも幾つかオプションがあります。詳細はドキュメントをご覧ください。

Leave a Reply

Your email address will not be published. Required fields are marked *