Jinja2をDjangoで使うためにドキュメント読みながら比較してみた

この記事はDjango Advent Calendar2016の16日目の記事です。

# Jinja2とは
簡単に言うと、Python製のテンプレートエンジンです。
公式ページ:  http://jinja.pocoo.org/
Djangoのテンプレートエンジンにインスパイアされているので、パッと見はDjangoのデフォルトのテンプレートエンジンと同じです。Jinja2はDjangoのテンプレートエンジンより機能が豊富で、HTMLやXMLの記述専用のテンプレートエンジンではなくLaTexやメールといった他の用途にも使うことができます。

Djangoの1.8より公式にサポートされています。（ライブライのインストールは必須です）

ちなみに、名前の由来は`神社を英訳するとTemple、TemplateとTempleは発音が似てる　→　Jinja`らしいですw

## 調べようと思った経緯
僕はDjangoに関しては初心者なので、とりあえずデフォルトのテンプレートエンジンを使っておくかとお言うことでDjangoでJinja2を使ったことはありません。[別の用途](http://qiita.com/zabeth129/items/b0ff3a1a927b0c70c80c)(自分の記事ですみませんw)で使ったことはありますが、あまり特殊なことはしてないので、ドキュメントもそんなに読んだことはありません。

~~ウェブフレームワークの開発はDjangoよりRailsのほうが慣れていることもあり、本心としてはRuby製のSlimを使いたいなと心から思っています~~ もっと便利なテンプレートエンジンがあって開発が楽になるなら使いたいなと思って、今回はDjangoでの用途に絞ってJinja2を調べることにしました。

DjangoでもSlimライクなテンプレートエンジンもあるらしいですが、情報が少なくて調べるのがめんどくさそうなのでやめました。


**この記事ではDjangoに関連したことだけ書くので、他の用途での使い方は取り扱いません。**


## 実行環境
実際にDjangoのテンプレートをJinja2に置き換えて、というのは大変そうだったので、今回は既存のプロジェクトのごく一部をお試しで入れ替えただけです。
次の導入の項目でも書きますが、デフォルトのテンプレートエンジンとJinja2が１つのプロジェクト内に混在していました。
**Python3.3以上は完全にサポートしているわけではないっぽい**ので、3.4以上を使っている場合は注意が必要かと思います。
ただ、テスト自体は通っているので、バグが有っても小さいものだけだろうとのことです。
http://jinja.pocoo.org/docs/dev/intro/#experimental-python-3-support


## 導入
Djangoのsettings.pyのTEMPLATEを以下のように書き換えます。
デフォルトではJinja2はjinja2ディレクトリにテンプレートファイルを探しに行くので、いつもの状態で`BACKEND`だけJinja2に切り替えたのでは動きません。
各アプリのtemplatesディレクトリ名をjinja2に変えるとか、`DIRS`で明示的に指定してあげる必要があるっぽいです。
下記の例ではいつもの（？）設定にJinja2の設定を追加する形にしています。

ローカルの開発環境ではdjango_debug_toolbarなどを入れていますが、これらのライブラリのテンプレートにパスを通すためには、いつものテンプレート設定も入れておく必要がありました。本番環境ではこれらのライブラリは利用せず、自身で定義したテンプレートしか（たぶん）使わないので、Jinja2の設定だけでよさそうです。

```py3
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.jinja2.Jinja2',
        'DIRS': [os.path.join(BASE_DIR, 'templates/jinja2')],
        'APP_DIRS': True,
    },
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

```

## Djangoとの違い
ドキュメントは充実していますが、Djangoのテンプレートエンジンとして使うには関係ない箇所も多いので、とりあえず下記URLをバーっと眺めると何ができるのかわかる気がします
http://jinja.pocoo.org/docs/dev/templates/#synopsis

Djangoインスパイアといいつつ、細かい仕様などで違う点はたくさんあるので、大きな違いだけ紹介します。

### メソッド実行時の記述の違い
JinJa２ではテンプレート上でもPythonライクに処理を書けます。
下記のように、Djangoでは（）がないですが、Jinja2では（）を付けます。
Django: `{% for page in user.get_created_pages %}`
Jinja2: `{% for page in user.get_created_pages() %}`
このお陰でテンプレート側でDjangoのモデルに[order_byを追加する](http://jinja.pocoo.org/docs/dev/faq/#how-compatible-is-jinja2-with-django)といったことができますが、テンプレート側でそういう記述をガッツリするのはイケてない気もしますねw

### マクロ
http://jinja.pocoo.org/docs/dev/templates/#macros
Djangoでは最初から用意されている処理以外をテンプレート上で行う場合は独自のテンプレートタグを定義したと思うのですが、Jinja2ではmacroというものを使って定義します。テンプレート内で定義したmacroはcallを使うことで再利用できます。詳細は省きますw

### いろんな演算子、フィルター（テンプレートタグ？）を使える
http://jinja.pocoo.org/docs/dev/templates/#list-of-builtin-filters
びっくりするくらい多くのフィルターがあります。ざっとみたかんじ、Pythonの配列や文字列、数字のオブジェクトがそれぞれに使えるor持っているメソッドは割と使える印象です。

http://jinja.pocoo.org/docs/dev/templates/#math
Djangoでテンプレート上で四則演算をしたいときは[django-mathfilter](https://github.com/dbrgn/django-mathfilters)を使っているのですが、Jinja2なら必要ないっぽいですね。地味ですけどこれは嬉しいです。比較演算子もたくさんありますね。

いちいち自分でテンプレートタグを作って使うのに比べたら圧倒的楽ですね。

### 変数の取扱い
例えば、次の変数をテンプレートで表示したい時、

```py3
foo = {"bar": 1}
```

Djangoのデフォルトのテンプレートの場合は

```html+jinja
foo.bar
```

になり、`foo["bar"]`という記述はできませんが、Jinja2の場合は`foo["bar"]`も利用できます。
dictの変数をドットでアクセスするのはいつも違和感があったのでこれも嬉しいです。

### グローバル変数の取扱
http://qiita.com/ryu22e/items/e50f8a3fbd6fe836c1b4
すでに記事を書いてくださっている方がいるので書きません。
Djangoのデフォルトのテンプレートエンジンだとcontext_processorが該当すると思うのですが、これは自作したことがないのでグローバル変数をセットできる事自体がJinja2の長所かどうかはちょっとよくわかってませんw

## まとめ
思っていたより機能が多く、ざっくりとした記事になってしまいました。

非常に多機能ですぐ使いたいなと思う反面、Djangoインスパイアといいつつ、細かな相違点も多く、既存のプロジェクトをJinja2に置き換えるのはちょっとめんどくさそうだなという印象を受けました。Railsでslimに切り替える場合には変換コマンドがあるので割と気軽に乗り換えられましたが、Jinja2はちゃんと全部チェックしていかないと無理そうですね。新規でアプリを作っていくときには試してみたいです。

また、そもそもテンプレート側にロジックを詰め込んだり、データを触りまくるのもよくないとは思うので、Jinja2を使うなら特にそこを気をつけないといけないなと思いました。ドキュメントにも同様のことが書かれてますね。
http://jinja.pocoo.org/docs/dev/faq/#isn-t-it-a-terrible-idea-to-put-logic-into-templates