PythonのWebフレームワークTornadoを使ってみる その2

# はじめに

最近[Tornado](http://www.tornadoweb.org/en/stable/)で遊んでいるので、その使い方をまとます。

今回は、テンプレートを使ってみます。使ってみるだけで解説はあまりしていません。次回に期待。なお、質問や要望があればお答えします。

## 実行環境

私の実行環境は以下の通りですが、Pythonが動作する環境なら問題ないと思います。

* CentOS release 6.5 (Final)
* Python 2.6.6

## 関連記事
* [PythonのWebフレームワークTornadoを使ってみる その1](http://qiita.com/intermezzo-fr/items/71caf7646cb16ef74ea0)

# テンプレートエンジンとは
テンプレートエンジンは、テンプレート（ひな形）と入力データを合成して、文字列を作る仕組みです。今回はPythonにおけるWebテンプレートエンジンの話に限定します。この場合、テンプレートエンジンとは、HTMLのテンプレート内に部分的にPythonコードを埋め込んで、最終的にHTMLを生成する仕組みのことです。小難しいことが知りたい方は、以下のWikipedia記事を参照するか、Googleで調べるといいでしょう。

* [Wikipedia \- テンプレートエンジン](http://ja.wikipedia.org/wiki/%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3)
* [Wikipedia - Webテンプレート](http://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%83%96%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88)



# Tornadoのテンプレートエンジン
百聞は一見にしかずということで、まずはテンプレートエンジンを使った例を示します。[前回](http://qiita.com/intermezzo-fr/items/71caf7646cb16ef74ea0)使ったindex.htmlを改造してみます。なお、ディレクトリ構成は[前回](http://qiita.com/intermezzo-fr/items/71caf7646cb16ef74ea0)のものを引き継いでいます。
非常につまらない例ではありますが、現在時刻を表示してみましょう。

## コード
前回からの変更点は以下の通りです。

* {% from datetime import datetime %}を追加
* \<p>{{datetime.now()}}\</p>を追加

```jinja
<!DOCTYPE html>
<html>
  <head>
    <title>Hello, world</title>
    <link rel="stylesheet" href="{{ static_url("style.css") }}"/>
    {% from datetime import datetime %}
  </head>
  <body>
    <div id="container">
      <div id="main">
          <p>Hello, world</p>
          <p>{{datetime.now()}}</p>
      </div>
    </div>
  </body>
</html>
```
## 実行例
ブラウザでアクセスすると現在時刻が取得できます。
![helloworld.png](https://qiita-image-store.s3.amazonaws.com/0/37377/978287d9-f2df-17b1-709b-509af5623747.png)

## 解説
Pythonではおなじみの以下のコードを{%と%}（もしくは、{{と}}）で囲んでHTML内に直接記述しているだけです。

```py
# datetimeモジュールからdatetimeをインポート
from datetime import datetime
# datetime.nowメソッドで現在時刻を取得
datetime.now()
```

いまさらですが、[前回](http://qiita.com/intermezzo-fr/items/71caf7646cb16ef74ea0)しれっと使っていた

```html+jinja
{{ static_url("style.css") }}
```

もテンプレートエンジンの機能でした。

{%と%}（もしくは、{{と}}）で囲んだ文字列を評価した結果で置換されます。簡単ですね。
Tornadoのテンプレートエンジンでは、基本的にHTMLファイル内で{%と%}（もしくは、{{と}}）でPythonコードを囲むと、その評価結果がHTMLに埋め込まれます。

for, while, if, try-cxceptなどの制御構造も書くことができます。

* {% for *var* in *expr* %}...{% end %}
* {% while *condition* %}... {% end %}
* {% if *condition* %}...{% elif *condition* %}...{% else %}...{% end %}
* {% try %}...{% except %}...{% finally %}...{% else %}...{% end %}

テンプレート内変数の定義もできます。

* {% set *x* = *y* %}

後でもっとちゃんとまとめようと思いますが、もっと詳しく知りたい方はTornadoのマニュアル[tornado.template — Flexible output generation](http://www.tornadoweb.org/en/stable/template.html)をご覧ください。

# サーバープログラムの計算結果を表示する
ここからは、サーバープログラム(server.py)の計算結果を受け取るにはどうすればいいか説明します。
post()メソッドやget()メソッドの説明は次回以降にすることとして、とりあえず使ってみます。
就職活動の時にお世話になる文字数をカウントするプログラムを書いてみましょう。

## ディレクトリ構成
```bash
$ tree --charset=x
.
|-- server.py
|-- static
|   `-- style.css
`-- templates
    |-- index.html
    `-- result.html
```

## コード

index.htmlで発行されたPOSTリクエストの結果をpost()メソッドで受け取り、result.htmlに変数len_bodyを渡して表示します。
つまらない例のように見えますが、ここまでできればPythonによる計算結果の受け渡しができるので、CGI全盛期のWebアプリケーションは書けるようになっているはずです。

```py:server.py
#!/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
import os
import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("index.html")

    def post(self):
        body = self.get_argument('body')

        len_body = len(body)

        self.render("result.html",
                    len_body = len_body
                    )


application = tornado.web.Application([
    (r"/", MainHandler)
    ],
    template_path=os.path.join(os.getcwd(),  "templates"),
    static_path=os.path.join(os.getcwd(),  "static"),
)

if __name__ == "__main__":
    application.listen(8888)
    print("Server is up ...")
    tornado.ioloop.IOLoop.instance().start()
```

pタグにつけていたスタイルを削除します。

```css:style.css
body {
  font-family:'Lucida Grande', 'Hiragino Kaku Gothic ProN', 'ヒラギノ角ゴ ProN W3', "ＭＳ Ｐゴシック", sans-serif;
  width: 80%;
  margin: 0 auto;
}
```

index.htmlで文字数を計算したい文字列を入力する画面を表示します。

```jinja:index.html
<!DOCTYPE html>
<html>
  <head>
    <title>文字数カウンタ</title>
    <link rel="stylesheet" href="{{ static_url("style.css") }}"/>
  </head>
  <body>
    <div id="container">
      <div id="main">
        <form method="post" action="/">
          <textarea name="body" cols="40" rows="4"></textarea>
          <input type="submit">
        </form>
      </div>
    </div>
  </body>
</html>
```

result.htmlで計算結果を表示します。

```jinja:result.html
<!DOCTYPE html>
<html>
  <head>
    <title>文字数カウンタ</title>
    <link rel="stylesheet" href="{{ static_url("style.css") }}"/>
  </head>
  <body>
    <div id="container">
      <div id="main">
          <p>{{len_body}}</p>
      </div>
    </div>
  </body>
</html>
```
## 実行例
確かに文字数がカウントできました。（環境によって文字数が異なるかもしれません。）
![helloworld.png](https://qiita-image-store.s3.amazonaws.com/0/37377/71908e57-8d09-20c9-9ee3-0ddcfcf2643c.png)
![helloworld.png](https://qiita-image-store.s3.amazonaws.com/0/37377/8d7eb267-d642-353b-1807-f12a3504dab2.png)


# 次回の予定
文字数カウントを拡張します。気が向いたら、TF/IDFによる類似度検索くらいまで書くかもしれません。