08:テンプレートを使ったHTML生成(08: HTML Generation With Templating)

ほとんどのWebフレームワークはプログラミングコードにHTMLを埋め込んでいません。代わりにデータをテンプレートシステムに渡します。このステップではPyramidでHTMLテンプレートを使用する際の基本を見ていきます

背景(Background)

ああ、私たちは独自の「レスポンス」を作成してレスポンスボディにHTMLを埋めこみました。通常はPythonに直接HTML文字列を埋め込むのではなく、テンプレート言語を使用します。

Pyramidは特定のデータベースシステムやフォームライブラリなどを強制しません。交換可能性を奨励します。これは幸運なことにテンプレートにも当てはまります。開発者はテンプレート言語についての強い見解を持っています。Pyramid1.5a2以降、Pyramidはテンプレート言語をバンドルしていません。

しかしながら、テンプレート言語は Jinja2、Mako、Chameleonと強い結びつきがあります。このステップでは、pyramid_chameleon をプロジェクトに追加する方法を見たあとでテンプレートを使用するようにビューを変更します。

目標(Objectives)

  • Pyramidアドオンの pyramid_chameleon を有効にします。
  • テンプレートファイルからHTMLを生成します。
  • テンプレートをビューコードの「レンダラー」として接続します。
  • シンプルなデータを返すようにビューコードを変更します。

手順(Steps)

  1. 前回のパッケージを新しいプロジェクトの出発点として使うことから始めましょう:

    $ cd ..; cp -r views templating; cd templating
    
  2. この手順は pyramid_chameleon に依存するので、templating/setup.py の依存関係として追加してください:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    from setuptools import setup
    
    requires = [
        'pyramid',
        'pyramid_chameleon',
        'waitress',
    ]
    
    setup(name='tutorial',
          install_requires=requires,
          entry_points="""\
          [paste.app_factory]
          main = tutorial:main
          """,
    )
    
  3. これで、開発モードを有効にできます:

    $ $VENV/bin/pip install -e .
    
  4. We need to connect pyramid_chameleon as a renderer by making a call in the setup of templating/tutorial/__init__.py:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    from pyramid.config import Configurator
    
    
    def main(global_config, **settings):
        config = Configurator(settings=settings)
        config.include('pyramid_chameleon')
        config.add_route('home', '/')
        config.add_route('hello', '/howdy')
        config.scan('.views')
        return config.make_wsgi_app()
    
  5. templating/tutorial/views.py はもはやHTMLを持っていません:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    from pyramid.view import view_config
    
    
    # First view, available at http://localhost:6543/
    @view_config(route_name='home', renderer='home.pt')
    def home(request):
        return {'name': 'Home View'}
    
    
    # /howdy
    @view_config(route_name='hello', renderer='home.pt')
    def hello(request):
        return {'name': 'Hello View'}
    
  6. 代わりに templating/tutorial/home.pt をテンプレートとして持っています:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <title>Quick Tutorial: ${name}</title>
    </head>
    <body>
    <h1>Hi ${name}</h1>
    </body>
    </html>
    
  7. 便宜上 templating/development.ini テンプレートを pyramid.reload_templates で自動的にリロードするには、次のように変更します:

    [app:main]
    use = egg:tutorial
    pyramid.reload_templates = true
    pyramid.includes =
        pyramid_debugtoolbar
    
    [server:main]
    use = egg:waitress#main
    listen = localhost:6543
    
  8. templating/tutorial/tests.py のユニットテストはデータに焦点を当てます:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    import unittest
    
    from pyramid import testing
    
    
    class TutorialViewTests(unittest.TestCase):
        def setUp(self):
            self.config = testing.setUp()
    
        def tearDown(self):
            testing.tearDown()
    
        def test_home(self):
            from .views import home
    
            request = testing.DummyRequest()
            response = home(request)
            # Our view now returns data
            self.assertEqual('Home View', response['name'])
    
        def test_hello(self):
            from .views import hello
    
            request = testing.DummyRequest()
            response = hello(request)
            # Our view now returns data
            self.assertEqual('Hello View', response['name'])
    
    
    class TutorialFunctionalTests(unittest.TestCase):
        def setUp(self):
            from tutorial import main
            app = main({})
            from webtest import TestApp
    
            self.testapp = TestApp(app)
    
        def test_home(self):
            res = self.testapp.get('/', status=200)
            self.assertIn(b'<h1>Hi Home View', res.body)
    
        def test_hello(self):
            res = self.testapp.get('/howdy', status=200)
            self.assertIn(b'<h1>Hi Hello View', res.body)
    
  9. 今度はテストを実行します:

    $ $VENV/bin/py.test tutorial/tests.py -q
    ....
    4 passed in 0.46 seconds
    
  10. Pyramidアプリケーションを以下のように実行します:

    $ $VENV/bin/pserve development.ini --reload
    
  11. ブラウザでhttp://localhost:6543/ と http://localhost:6543/howdy を開いてください。

分析(Analysis)

良いように見えます。Pythonコードに焦点を当てています。 @view_config デコレータは、テンプレートファイルを指す renderer を指定します。ビューはシンプルにデータを返却してテンプレートに供給されます。両方のビューで同じテンプレートを使用したことに注意してください。

テストへの影響に注目してください。ビューコードとデータ指向の契約を結ぶことに重点を置けます。