テンプレートからの動的コンテンツの生成


Python Guestbook コード ウォークスルーのこのパートでは、動的なウェブ コンテンツを生成するための Jinja テンプレートの使用方法について説明します。

このページは複数ページからなるチュートリアルの一部です。設定などの手順を最初から見るには、ゲストブックの作成に移動してください。

コードに HTML が埋め込んであると、コードを追いにくくなり保守が困難です。このような場合はテンプレート システムを使用すると便利です。テンプレート システムは、アプリケーションのデータが出現する場所を示す特殊な構文を使って、HTML を別ファイルとして維持します。Python 用のテンプレート システムには、EZTCheetahClearSilverQuixoteDjangoJinja2 など、数多くのものがあります。好みのテンプレート エンジンをアプリケーション コードにバンドルして使用できます。

手軽な方法としては、App Engine に Django と Jinja2 のテンプレート エンジンが搭載されています。

Jinja2 テンプレートの使用

app.yaml ファイルには、必須ライブラリとしての最新バージョンの jinja2 がリストされています。本番環境のアプリケーションでは、version: latest ではなく実際のバージョン番号を使用してください。

libraries:
- name: webapp2
  version: latest
- name: jinja2
  version: latest

アプリによって jinja2 がインポートされ、jinja2.Environment オブジェクトが作成されます。

import os
import urllib

from google.appengine.api import users
from google.appengine.ext import ndb

import jinja2
import webapp2

JINJA_ENVIRONMENT = jinja2.Environment(
    loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
    extensions=['jinja2.ext.autoescape'],
    autoescape=True)

MainPage リクエスト ハンドラの get メソッドは Key-Value ペアのディクショナリを形成し、これを template.render に渡します。

class MainPage(webapp2.RequestHandler):

    def get(self):
        guestbook_name = self.request.get('guestbook_name',
                                          DEFAULT_GUESTBOOK_NAME)
        greetings_query = Greeting.query(
            ancestor=guestbook_key(guestbook_name)).order(-Greeting.date)
        greetings = greetings_query.fetch(10)

        user = users.get_current_user()
        if user:
            url = users.create_logout_url(self.request.uri)
            url_linktext = 'Logout'
        else:
            url = users.create_login_url(self.request.uri)
            url_linktext = 'Login'

        template_values = {
            'user': user,
            'greetings': greetings,
            'guestbook_name': urllib.quote_plus(guestbook_name),
            'url': url,
            'url_linktext': url_linktext,
        }

        template = JINJA_ENVIRONMENT.get_template('index.html')
        self.response.write(template.render(template_values))

このディクショナリを入力データとして受信する index.html テンプレートに従って、ページがレンダリングされます。

{% for greeting in greetings %}
<div class="row">
  {% if greeting.author %}
    <b>{{ greeting.author.email }}
      {% if user and user.user_id() == greeting.author.identity %}
        (You)
      {% endif %}
    </b> wrote:
  {% else %}
    An anonymous person wrote:
  {% endif %}
  <blockquote>{{ greeting.content }}</blockquote>
</div>
{% endfor %}

JINJA_ENVIRONMENT.get_template(name) メソッドは、テンプレート ファイルの名前を受け取り、テンプレート オブジェクトを返します。template.render(template_values) 呼び出しは、値のディクショナリを受け取り、レンダリングしたテキストを返します。このテンプレートは Jinja2 テンプレート構文を使用して値にアクセスして反復処理し、各値のプロパティを参照できます。