読者です 読者をやめる 読者になる 読者になる

GAE/Pythonで、テンプレートを利用したHTMLの表示

http://〜.appspot.com/page/test.html
などのURLをPythonのテンプレート機能を利用して表示する方法です。


app.yaml

handlers:
- url: /template/(.*)
  script: /template/\1

- url: /page/.*
  script: test.py

1つ目のurlでは、テンプレート用のHTMLファイルが置いてある場所を定義しています。
HTMLファイルなので、"static_dir"でよいかと思っていたんですが、
scriptで指定しないと動かないようです。
2つ目のurlでは処理するPythonスクリプトファイルを指定しています。
今回は"/paga/〜"でリクエストがあった場合、すべてのリクエストを1つのスクリプトで処理することになっています。
(内部で処理するクラスを分けることは可能です)


/test.py

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
import os
import random
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

class MyData():
    stageNo = 0
    size = 0

class MainPage(webapp.RequestHandler):
    def get(self):
        index = 0 if len(self.request.get('index')) == 0 else int(self.request.get('index'));

        summary = {}
        summary['count'] = 3
        summary['index'] = index;

        myDatas = []
        for i in xrange(3):
            m = MyData()
            m.stageNo = i + index
            m.size = random.randint(1, 20)
            myDatas.append(m)

        template_values = {
                           'summary': summary,
                           'myDatas': myDatas,
                           }

        path = os.path.join(os.path.dirname(__file__), 'template', 'test.html')
        html = template.render(path, template_values)
        self.response.out.write(html)

application = webapp.WSGIApplication([('/page/test.html', MainPage),
                                      ], debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()

辞書型である'summary'と、オブジェクトのリストである'mydatas'を設定しています。
設定値は適当なものを入れてみました。
それを'template_values'という辞書型に設定しています。


'path'にはテンプレートHTMLファイルのパスを設定しています。
実際に'/template/test.html'というファイルを利用するため、'join'を利用してこのように記述しています。
あとは'template.render'にパスとパラメータを渡して、出力します。


'webapp.WSGIApplication'の引数に'/page/test.html'となっているため、該当のURLでアクセスした場合に'MainPage'の関数が呼ばれます。
複数のURLを1つのクラスで処理したい場合は、'/page/.*html'などとしたら出来るようです。
(つまり、上記は'/page/test.html'と記述してあるため、'/page/testahtml'などでもアクセス出来てしまいます。
 本来は'/page/test\.html'と記述するべきかもしれません。)


/template/test.html

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>テスト</title>
</head>
<body>
	<!-- ヘッダ -->
	<header>
		<h1>テスト</h1>
	</header>

	<div id="summary">
		登録件数:{{ summary.count }}<br>
		インデックス:{{ summary.index }}
	</div>
	<div id="pager">
		{{ pager }}
	</div>
	<div id="stages">
		<ul>
{% for myData in myDatas %}
			<li>StageNo:{{ myData.stageNo }}, size:{{ myData.size }}</li>
{% endfor %}
		</ul>
	</div>
</body>
</html>

'{{'と'}}'で囲まれた箇所は、JSPの'<%='と'%>'と同じような感じかと思います。
(ただ、どちらかと言うと、JSP2.0以降のEL式の方が似てる気がします。)
'{%'と'%}'で囲まれた箇所は、JSPの'<%'と'%>'と同じような感じかと思います。


以上で'/page/test.html'とアクセスされた場合に、Pythonのスクリプトで処理した結果をHTMLに出力することができます。


ちなみに、HTMLを利用すると、JavaScriptのファイル・CSSファイルなどが必要になるかと思います。
その場合のapp.yamlの設定は下記のように出来ます。

- url: /js
  static_dir: js

- url: /css
  static_dir: css

この設定によって、あとは普通に

<script src="/js/jquery-1.6.4.js"></script>

のように記述するとJavaScriptファイルを読み込めます。