Django と South と custom sql
自前で create table したい
Django を使っていて Django の ORM はそのまま使いたいんだけど、create table は自前で行いたい場合があります。
良くあるのは、partition 切りたい場合とか。
MySQL の range partition を使うには Primary Key を 複合Primary Key にする必要があるのですが、Djangoは 複合Primary Key を許可していません。
なので、そのような場合は自前で create table文 を書いて実行する必要があります。
class PartitionExample(models.Model): log = models.TextField(verbose_name=u'ログ') created_at = models.DateTimeField(verbose_name=u'作成日時', auto_now_add=True) class Meta: db_table = 'partition_example' managed = False # こうすると syncdb でモデルが作られない
こんなモデルを書いて
CREATE TABLE partition_example ( id int AUTO_INCREMENT, log TEXT, created_at DATETIME, CONSTRAINT PRIMARY KEY (id, created_at) ) PARTITION BY RANGE COLUMNS (created_at) ( PARTITION pfuture VALUES LESS THAN (maxvalue) );
それと構造が等しい sql を書く。
その sql を appname/sql/partitionexample.sql に置くと、syncdb する時に自動的に sql を実行してモデルを作成してくれるという案配です。
いやー Django って良く出来てますね。
ところが、このままだと South 環境では上手く行きません。
South の場合
South を入れていると syncdb を上書いてしまっているので、sql を実行してくれないのです。
そこで、どうするかと言うと、schemamigration --init を実行すると managed = False のモデルを無視した migration ファイルが出来ます。
class Migration(SchemaMigration): def forwards(self, orm): pass def backwards(self, orm): pass
他にモデルがない場合はこんなの。
これを自前で sql を実行するように修正します。
class Migration(SchemaMigration): def forwards(self, orm): with open(sql_file_path) as f: sql = f.read() db.execute(sql) def backwards(self, orm): pass
これでOK。あとは普通に migrate するだけです。
これ以降の変更は schemamigration --auto で自動的に migration ファイルを作ってくれるので、普通に South を使う時と何も変わりません。