[Dd]enzow(ill)? with DB and Python

DBとか資格とかPythonとかの話をつらつらと

Pythonで一番小さいWEBフレームワークbottle.py その8(TEMPLATE)

最初の頃はbottleの話をよく書いてましたが最近は疎かになってましたので久しぶりです。今回はtemplate engineについてまとめておきます。

テンプレートエンジン(template engine)

WEBアプリケーションのUIは当然HTMLで作成しますが、生のHTMLは固定された内容しか表現できません。しかし、WEBアプリケーションでは、複数ある商品の繰り返しを表示したりログインしているユーザ名を表示したりと、動的に変わる部分を表現できなければいけません。

もちろん以下のようにPythonのコードで動的に文字列としてHTMLを組み上げることで動的なHTMLを作成することは可能です。

@get('/test')
def get_test():
    user_name = 'ログインしているユーザ名'
    return """
    <body>
        <h2> {{user_name}} </h2>
    </body>
    """.format(
        user_name=user_name
    )

Pythonで生成する文字列にHTMLを組み込むわけです。しかし、実際のサイトではかなり複雑なHTMLを使用するのでそのようなHTMLをこの方法で用意するのはメンテナンス性に欠きます。そこでテンプレートエンジンを使用します。テンプレートエンジンは先程とは逆にHTMLにPythonのコードを埋め込みます。

templateの使い方

ディレクトリ構成は以下の様になっています。

.
├── template.py
└── views
    └── sample.html

template.pyは以下になっています。

# coding:utf-8
from bottle import run, route, template


@route("/")
def index():
    username = 'test name'
    return template('sample', username=username)


if __name__ == "__main__":
    run(host='localhost', port=8080, reloader=True, debug=True)

views/sample.htmlは以下のHTMLファイルです。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>テンプレートエンジン</title>
</head>
<body>

<h2>WELCOME: {{ username }}</h2>

</body>
</html>

この状態でpython template.pyとして起動してから、http://localhost:8080/にアクセスするとWELCOME: test nameと表示されます。views/sample.htmlは見た目上ほとんどHTMLですが{{ username }}だけが異なります。ここがテンプレートエンジンによって処理され、動的に値が設定されます。

template('sample', username=username)という部分は以下の流れで動作します。

  • sample.htmlというファイルをviews配下から捜索
  • sample.htmlを読込
  • {{ xxx }}というテンプレートエンジン用の記法をチェック
  • username='test name'を読み込んだ内容に当てはめて置き換え
  • 置き換え後のHTMLを生成し、クライアントへ返送

なお、sample.htmlは拡張子が必ずしもhtmlである必要はなく['tpl', 'html', 'thtml', 'stpl']の何れかであれば良いです。また、viewsというディレクトリも以下の様にbottle.TEMPLATE_PATHに追加することで変更可能です。

import bottle
bottle.TEMPLATE_PATH += ['./other_path']

なお、テンプレートに渡すデータが少ないときはtemplate('sample', username=username)のように直接指定しても良いですが、数が多い時は以下の様にしたほうが楽です。

@route("/")
def index():
    context_data = {
        'username': 'test name',
        'data1': 1,
        'data2': 2,
        'data3': 3,
    }
    return template('sample', **context_data)

templateの記法

bottleに標準で用意されているテンプレートエンジンはSimpleTemplate Engineと呼ばれるものです。このテンプレートエンジンで利用できる記法を確認します。以下の形でデータをテンプレートに渡します。

@route("/")
def index():
    context_data = {
        'username': 'test name1',
        'is_admin': False,
        'todo_list': [
            'todo1',
            'todo2',
            'todo3',
            'todo4',
        ]
    }
    return template('sample', **context_data)

テンプレート側は以下です。

<body>

<h2>WELCOME: {{ username }}</h2>

% if is_admin:
    <p>管理者モード</p>
% else:
    <p>一般モード</p>
% end

<ul>
% for todo in todo_list:
    <li>{{ todo }}</li>
% end
</ul>
</body>

<h2>WELCOME: {{ username }}</h2>という箇所は先程からでていましたが、{{ xxx }}で指定したPythonの変数が展開されます。

%で始まる行はPythonのコードとして評価されます。ただし、インデントでのブロック表現ができないため% endでブロックの終了を明示する必要があります。そのため上述例のようにforifendとセットで用いられます。

まとめ

WEBアプリケーションでUI部分で用いられるテンプレートについて簡単にまとめました。bottleのテンプレートエンジンはテンプレートファイルの分割等の高度な機能も用意されていますので詳しくはdocumentを御覧ください。