Tornado入門（３）：テンプレートを使った開発【実践編】

# はじめに
本連載では、Python上で動作するWebサーバ&WebアプリケーションフレームワークであるTornadoでアプリケーション開発を行う方法について紹介します。本連載で扱う内容は、次のとおりです。

* Tornadoの特徴
* Tornado利用のための環境設定手順
* Hello, Worldアプリケーションの作成
* データベースと連携したアプリケーションの作成
* その他、役立つTornado関連のテクニック

　前回は、ハンドラからテンプレートに値を渡す方法を解説しました。これにより、動的なコンテンツ生成が可能になりました。今回はさらなるテンプレートの機能について解説していきます。具体的には、テンプレートの継承を使用したアプリケーションの構築について解説していきます。

<!-- 今回は、Tornadoのテンプレートエンジン機能を紹介します。-->

# 対象読者
* PythonによるWebアプリケーション開発に興味がある方
* Pythonを触ったことがある方
* Webアプリケーションの開発をこれから学ぶ方、もしくは学び始めたばかりの方

# 必要な環境
* Python 2.6 以上
* Tornado 4.2

# 関連記事
* [Tornado入門（１）：TornadoではじめるPythonWebフレームワーク](http://qiita.com/Hironsan/items/4e0345704cda5b661d9f)
* [Tornado入門（２）：テンプレートを使った開発入門 〜動的にページを生成する〜](http://qiita.com/Hironsan/items/d2d8f59ed2c2e8e63488)

# サンプルコード
* [サンプルコード](https://github.com/Hironsan/Introduction_Tornado/tree/master/03)

# 前回のおさらい
　[前回の記事](http://qiita.com/Hironsan/items/d2d8f59ed2c2e8e63488)では、名前を渡すと「Hello yourname!」のように表示するアプリケーションを作成しました。このアプリケーションの作成を通じて、動的なページ生成の基礎について理解したのでした。
<img width="370" alt="スクリーンショット 2015-10-26 16.01.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/77079/f04918fa-ba73-313d-94de-347a055954e9.png">

　前回はテンプレートファイルの数は一つしかありませんでした。しかし、実際のWebアプリケーションでは複数テンプレートを使用することがほとんどです。そこで、今回は複数テンプレートを使用した開発をしてみます。

　今回作るのはプログラミング言語の紹介サイトです。以下のようなイメージです。

![sample.jpg](https://qiita-image-store.s3.amazonaws.com/0/77079/a06c6a1b-17d9-aa5c-cf26-4c5e2975e00e.jpeg)

今回はテンプレートの継承という仕組みを学んでから作っていきます。

# テンプレートの継承
　テンプレートの継承とは、**既存のテンプレートを継承して新しいテンプレートを作る機能**のことです。既存のテンプレートを**親テンプレート**、継承して作るテンプレートを**子テンプレート**と呼ぶことにします。

<!--
このテンプレートの継承を行うには、子テンプレートファイルの最上部に {% extends "親テンプレートのファイル名" %} と書く必要があります。
-->
　テンプレートの継承では、親テンプレートに自分のサイトで共通に使われる要素を入れておき、その中に子テンプレートで上書きできるブロック（block）を定義します。これにより、親テンプレートの再利用を可能にします。例を見てみましょう。

```html+genshi:base.html
<html>
  <head>
    <title>{% block title %}デフォルトタイトル{% end %}</title>
  </head>
  <body>
    {% block content %}
      デフォルトコンテンツ
    {% end %}
  </body>
</html>
```

　このテンプレートを base.html と呼びましょう。この例では、 block タグを使って２つのブロック（{% block title %}{% end %}と{% block content %}{% end %}）を定義し、子テンプレートが値を埋められるようにしています。block タグの役割は、テンプレート中のタグで囲まれた部分を子テンプレートで上書きできることをテンプレートエンジンに知らせることにあります。

子テンプレートは以下のようになります:

```html+genshi
{% extends "base.html" %}

{% block content %}
  子テンプレートのコンテンツ
{% end %}
```
　最上部の extends タグが継承のカギです。このタグはテンプレートエンジンに対して、自分自身が他のテンプレートを拡張 (extend) していることを教えています。テンプレートエンジンがこのテンプレートを処理する際、まず親テンプレート（ここでは base.html）を探します。

　この時点で、テンプレートエンジンは base.html 内に２箇所の block が定義されていることに気づき、これらのブロックを子テンプレートの該当するブロックで置き換えます。出力は 以下のようになります:

```html+genshi
<html>
  <head>
    <title>デフォルトタイトル</title>
  </head>
  <body>
    子テンプレートのコンテンツ
  </body>
</html>
```
子テンプレートには title ブロックが定義されていないので、親テンプレートの値がそのまま使われます。


# アプリケーションの作成
## ディレクトリ構成
ディレクトリ構成は前回とほぼ同様です。違いはtemplatesにいくつかのファイルが加わったことです。

```shell-session
.
├── app.py
├── static
│   └── style.css
└── templates
    ├── base.html
    ├── index.html
    ├── php.html
    ├── python.html
    └── ruby.html
```
　templates 内のファイルは、 base.html が継承される親テンプレートであり、その他は base.html を継承して作成される子テンプレートです。機能としては、 index.html がトップページであり、その他は各言語の紹介ページです。

前回と同じく構成要素は以下の３つです。

* Pythonコード
* テンプレート
* CSS

## Pythonコード
今回実行するPythonコードは以下のようなものです。

```py
import os
import tornado.ioloop
import tornado.web
from tornado.web import url


class IndexHandler(tornado.web.RequestHandler):

    def get(self):
        self.render('index.html')


class PythonHandler(tornado.web.RequestHandler):

    def get(self):
        self.render('python.html')


class PHPHandler(tornado.web.RequestHandler):

    def get(self):
        self.render('php.html')


class RubyHandler(tornado.web.RequestHandler):

    def get(self):
        self.render('ruby.html')


BASE_DIR = os.path.dirname(__file__)

application = tornado.web.Application([
    url(r'/', IndexHandler, name='index'),
    url(r'/python/', PythonHandler, name='python'),
    url(r'/php/', PHPHandler, name='php'),
    url(r'/ruby/', RubyHandler, name='ruby'),
    ],
    template_path=os.path.join(BASE_DIR, 'templates'),
    static_path=os.path.join(BASE_DIR, 'static'),
)

if __name__ == '__main__':
    application.listen(8888)
    tornado.ioloop.IOLoop.current().start()
```
　前回から特に新しいことはしていません。新しい点を一つ挙げるとするならば、URLを設定するときにurl関数を使い、引数として name を渡していることです。これにより、URLの逆引きを行うことができます。URLの逆引きは、**逆引き用の関数に名前を渡すとその名前に対応したURLに変換**されるイメージです。例えば、今回のようなURL設定の場合、逆引き用の関数に "python" という文字列を渡せば、 "/python/" というURLに変換されます。なぜこのようなことが可能なのかというと、 "/python/" というURLをurl関数を用いて設定する際に、その name 引数に "python" という文字列を渡しているからです。
　なお、逆引きはテンプレート内で使用しています。

## テンプレート
今回表示に使うテンプレートは以下の５つです。
まずは、base.html。これが今回の親テンプレートです。

```html+jinja:base.html
<!DOCTYPE html>
<html lang="ja">
    <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width, initial-scale=1">

      <title>{% block title %}{% end %}</title>

      <!-- CSS -->
      <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
      <link href="{{ static_url('style.css') }}" rel="stylesheet">

    </head>

    <body>

        <nav class="navbar navbar-inverse navbar-fixed-top">
            <div class="container">
                <div class="navbar-header">
                    <a class="navbar-brand" href="{{ reverse_url('index') }}">Home</a>
                    <a class="navbar-brand" href="{{ reverse_url('python') }}">Python</a>
                    <a class="navbar-brand" href="{{ reverse_url('php') }}">PHP</a>
                    <a class="navbar-brand" href="{{ reverse_url('ruby') }}">Ruby</a>
                </div>
            </div>
        </nav>

        <div class="jumbotron">
            <div class="container">
                {% block content %}
                {% end %}
            </div>
        </div>

        <div class="container">
            <footer>
                <p>&copy; Company 2015</p>
            </footer>
        </div>

        <!-- JavaScript -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

    </body>
</html>
```
　このテンプレートファイルでは２つのブロック（{% block title %}{% end %}と{% block content %}{% end %}）を定義しています。この２つのブロックは子テンプレートによって置き換えられます。
　またナビゲーションバーの部分でreverse_url関数を使っているのがわかるでしょうか？この関数が先ほど説明したURLの逆引きを行うための関数です。


次に、index.html。これは base.html を継承して作成しています。トップページとして機能します。

```html+jinja:index.html
{% extends "base.html" %}
{% block title %}トップページ{% end %}
{% block content %}
    <h1>プログラミング言語の紹介</h1>
    <p>
        　こんにちは！このサイトではプログラミング言語の紹介をしています。
        具体的には、Python、PHP、Rubyの３つです。
        上のメニューから興味のある言語を選択して詳細をご覧ください。
    </p>
{% end %}
```
 extends を使って base.html を継承して作成している点と、 block を使って内容を置き換えていることを確認してください。

そして、php.html、python.html、ruby.htmlです。これらも base.html を継承して作成しています。それぞれ各言語の紹介ページとして機能します。

```html+jinja:php.html
{% extends "base.html" %}
{% block title %}PHPの紹介{% end %}
{% block content %}
    <h1>Hello, PHP!</h1>
    <p>
        　PHPとは、動的にHTMLデータを生成することによって、動的なウェブページを実現することを主な目的としたプログラミング言語、
        およびその言語処理系である。一般的には PHP と省略して用いられており、これは「個人的なホームページ」を意味する英語の
        "Personal Home Page" に由来する。
    </p>
    <p><a class="btn btn-primary btn-lg" href="https://secure.php.net/" role="button">もっと知る &raquo;</a></p>
{% end %}
```

```html+jinja:python.html
{% extends "base.html" %}
{% block title %}Pythonの紹介{% end %}
{% block content %}
    <h1>Hello, Python!</h1>
    <p>
        　Python（パイソン）は、広く使用されている汎用のプログラミング言語である。
        コードのリーダビリティが高くなるように言語が設計されていると主張され、その構文のおかげで、Cなどの言語に比べて、
        より少ないコード行数でプログラムを表現できると主張されている。小規模なプログラムから大規模なプログラムまで、
        さまざまなプログラムをクリアに書けるように、多くのコードが提供されている。
    </p>
    <p><a class="btn btn-primary btn-lg" href="https://www.python.org/" role="button">もっと知る &raquo;</a></p>
{% end %}
```

```html+jinja:ruby.html
{% extends "base.html" %}
{% block title %}Rubyの紹介{% end %}
{% block content %}
    <h1>Hello, Ruby!</h1>
    <p>
        　Ruby（ルビー）は、まつもとゆきひろ（通称 Matz）により開発されたオブジェクト指向スクリプト言語であり、
        スクリプト言語が用いられてきた領域でのオブジェクト指向プログラミングを実現する。
        また日本で開発されたプログラミング言語としては初めて国際電気標準会議で国際規格に認証された事例となった。
    </p>
    <p><a class="btn btn-primary btn-lg" href="https://www.ruby-lang.org/ja/" role="button">もっと知る &raquo;</a></p>
{% end %}
```
 これらも index.htmlと同様に、extends を使って base.html を継承して作成し、 block を使って内容を置き換えています。

## CSS
今回使うCSSファイルは以下の通りです。

```css
body {
  padding-top: 50px;
  padding-bottom: 20px;
}
```
特に言うこともないので、このCSSファイルについての説明は省かせていただきます。

# 実行
　前回と同じように、以下のコードを実行してサーバを立ち上げてください。

```shell-session
$ python app.py
```
その後、[http://localhost:8888/](http://localhost:8888/)にアクセスしてください。以下のようなページが表示されたはずです。
<img width="987" alt="result.png" src="https://qiita-image-store.s3.amazonaws.com/0/77079/8be30023-8d2d-5525-ef5f-4e5f54ea4092.png">

ナビゲーションバーのプログラミング言語名を選択してみてください。テンプレートの継承を使ってページが生成されていることがわかるはずです。


# まとめ
　今回は、テンプレートの継承を使用したアプリケーションの構築について紹介しました。extendsを使うことでテンプレートを継承し、block を使うことで子テンプレートからブロック内の内容を置き換えられることがご理解いただけたと思います。

　前回紹介したハンドラからの値の渡し方と今回紹介した継承の仕方を理解できれば、テンプレートを使った開発の基本は理解できたと言えます。あとはテンプレートで使える制御文や関数を知っていればスムーズに開発できます。次回はテンプレート内で使える制御文や関数について紹介していきます。

# 参考資料

* [（英語）tornado.template](http://www.tornadoweb.org/en/stable/template.html)
* [（英語）テンプレートとUI](http://tornadokevinlee.readthedocs.org/en/latest/guide/templates.html)