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

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 を使う時と何も変わりません。