日記

日々のことと、Python/Django/PHP/Laravel/nodejs などソフトウェア開発のことを書き綴ります

manage.pyサブコマンド(バッチ処理)とTemplateの有効活用

Modelに入るはずでしたが、予定を変更してコマンドラインからもっと有効的にDjangoを使う方法を載せておきます。
バッチ処理というキーワードで、マニュアルとかに書いてないんですもの。。。

Djangoシステムの有効利用

Djangoフレームワークは、Webだけに限らずshellや、自分で manage.py のサブコマンドを作成して利用することもできます。
Djangoの中で、manage.pyから使用できる機能は、「Command」と呼ばれています。

Commandの作り方

Commandは、Djangoアプリケーションの中で定義しますが、ディレクトリ構成がちょっと特殊です。
特殊なディレクトリ構成と言えば、カスタムタグやフィルターがありました。あれと似たような方法です。

アプリケーションのディレクトリの下に management/commands とパッケージ用のディレクトリを作ります。
それぞれに __init__.pyを配置することを忘れずに。
その中に、sample.pyなどとして Command 用の.pyファイルを作成します。

app_name/management/commands/sample.py

# vim*:fileencoding=utf8
from django.core.management.base import BaseCommand

class Command(BaseCommand):
  def handle(self, *args, **options):
    print 'call sample command.'

Commandはこんな感じの実装です。ポイントは、クラス名はCommandとしないといけないことで、一つの.pyファイルで定義できるコマンドは一つだけということになります。

自作のCommandをmanage.py経由で呼び出す

これを manage.pyから呼び出すわけですが、実行前に読み込まれているか確認できます。

python manage.py help

とすると、利用できるCommandが一覧で表示されます。この中に、sampleが入っていれば、Django側でCommandが認識されています。
表示されないときはディレクトリ構成、ファイル名、クラス名を確認して、settings.pyの INSTALLED_APPSに登録されているか確認します。

実際に呼び出すときは、syncdb や runserver似た感じで

python manage.py sample

となります。

CommandとTemplateを組み合わせる

Commandはユーティリティとしても使えますが、バッチ処理としても活用できると思います。バッチ処理で思いつくのは、集計レポート作成や定期的なメール送信など。。。 データベース上の検索結果をテキストに埋め込んだりということも多いと思います。
そこで、DjangoのTemplateを組み合わせることで、HTMLを出力している時と同じ Template システムを使ってメールとかCSVとかを出力することができます。sample.pyを少し書き換えます。

app_name/management/commands/sample.py

# vim*:fileencoding=utf8
from django.core.management.base import BaseCommand
from django.template import Context, Template

template_string = """
Hello {{ message }}!!
"""

class Command(BaseCommand):
  def handle(self, *args, **options):
    t = Template(template_string)
    params = { 'message': 'World' }
    print t.render(params)

ファイルでは無く、文字列から Templateクラスのインスタンスを作るようにしてみました。
これを manage.py経由で実行すると

Hello World!!

と表示されるはずです。
Template上では、Webの時と同じビルトインタグが利用できるので、ループや条件分岐なども全く同じ書き方が使えます。
ファイルを分けずに利用することもできるので、知っておくと便利です。

Templateの落とし穴

凄く便利なのですが注意点もあります。
Django の Template は HTML に特化して初期設定されていること。
動的な部分は、普通に出力されるように見えて、実は必要とあれば自動的にHTML用のエスケープがされています。
メールなどを送信するとき、CSVファイルでカラムをダブルクォートで括りたいとき、などが困ってしまいます。
そんな時は

{{ target|safe }}

として、safeフィルタを適用します。これを使うと、HTMLエスケープは行われずに、そのままの文字列が出力されます。

まとめ

Djangoのモデルを使いつつ、バッチ処理を実装したい時は Commandを使うと便利です。
カスタムタグなどに比べると自作する時のルールが多いですが、Djangoの便利機能をバッチ処理でも利用したいというときは、この方法で実装するとオシャレで良いと思います。