Pyramid Layout を使ったデモアプリ

demo の中で提供されるデモアプリケーションを使って Pyramid Layout が 動いているところを見てみましょう。

インストール

通常の Pyramid のやり方と同じです:

  1. virtualenv を作る
  2. env/bin/python demo/setup.py develop
  3. env/bin/pserve demo/development.ini
  4. ブラウザで http://0.0.0.0:6543/ を開く
  5. ヘッダーの Home Mako, Home Chameleon, Home Jinja2 リンクを クリックして、それぞれで使われるビューを見る

それではいくつかコードを見ていきましょう。

登録

Pyramid Layout は、プロジェクトの中で使用できる設定ディレクティブと デコレータを定義しています。それらをコードの中にロードする必要があります。 デモでは etc/development.ini ファイルでこれを行っています:

pyramid.includes = 
    pyramid_debugtoolbar
    pyramid_jinja2
    pyramid_layout

development.ini エントリーポイントは demo/__init__.py の中で 開始します:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from pyramid.config import Configurator

def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    config = Configurator(settings=settings)
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('home.mako', '/')
    config.add_route('home.chameleon', '/chameleon')
    config.add_route('home.jinja2', '/jinja2')
    config.scan('.layouts')
    config.scan('.panels')
    config.scan('.views')
    return config.make_wsgi_app()

これはすべて Configurator アクションです。ここでは各ビューの route を 登録しています。そして、登録のために demo/layouts.py, demo/panels.py, demo/views.py を scan します。

Layout

全体像から始めましょう: Layout によるグローバルな ルックアンドフィールです:

 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
from pyramid_layout.layout import layout_config


@layout_config(template='demo:templates/layouts/layout.mako')
@layout_config(
    name='chameleon',
    template='demo:templates/layouts/layout.pt'
    )
@layout_config(
    name='jinja2',
    template='demo:templates/layouts/layout.jinja2'
    )
class AppLayout(object):

    def __init__(self, context, request):
        self.context = context
        self.request = request
        self.home_url = request.application_url
        self.headings = []

    @property
    def project_title(self):
        return 'Pyramid Layout App!'

    def add_heading(self, name, *args, **kw):
        self.headings.append((name, args, kw))

@layout_config デコレータは Pyramid Layout から来たもので、 Layout を定義および登録することができます。この場合、 3つのデコレータを積み重ねています。それぞれのテンプレート言語に対して 1つずつ、3つの Layout を作っています。

ノート

最初の @layout_configname を持っていません。そのため それはビューがどの Layout が欲しいか特に指定しなかった場合に 得られる Layout になります。

21-24 行目は、テンプレートとテンプレートロジックをお互いの近くに置いておく ことの概念を例示しています。すべてのビューで project_title を表示する 必要があります。それはグローバルなルックアンドフィールの main template の一部です。そのため、それぞれのビューがデータ/ロジック を持つのではなく、グローバルな契約の一部としてこのロジックを layout の中の 1つの場所に置いています。

次に、これが3つの Layout のうちの1つに対するテンプレートの中で 使われている場所を見ましょう。この場合は demo/templates/layouts/layout.mako の Mako テンプレートです:

<title>${layout.project_title}, from Pylons Project</title>

ここで、重要な概念と、ある重要なマジックを見ることができます: テンプレート にはトップレベルの変数 layout があります。これは Layout クラス のインスタンスです。

ZPT の人々にとっては、 demo/templates/layouts/layout.pt にある マスターテンプレートを見ると先頭に不思議なものがあることに気がつくかも しれません: metal:define-macro はありません。 Chameleon は テンプレートがトップレベルのマクロになることを許すので、 Pyramid Layout は自動的に全テンプレートを main_template という名前のマクロに結び付けます。

ビューはどのようにして Layout を使用する方法を知るのでしょうか。 見てみましょう。

ビューを Layout に接続する

デモアプリには、いくつかの非常に単純なビューがあります:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pyramid.view import view_config

@view_config(
    route_name='home.mako',
    renderer='demo:templates/home.mako'
    )
@view_config(
    route_name='home.chameleon',
    renderer='demo:templates/home.pt',
    layout='chameleon'
    )
@view_config(
    route_name='home.jinja2',
    renderer='demo:templates/home.jinja2',
    layout='jinja2'
    )
def home(request):
    lm = request.layout_manager
    lm.layout.add_heading('heading-mako')
    lm.layout.add_heading('heading-chameleon')
    lm.layout.add_heading('heading-jinja2')
    return {}

再び3つの積み重なったデコレータと1つのcallableがあります。 デコレータはすべて通常の Pyramid @view_config のものです。

2つ目のデコレータは demo/templates/home.pt にある Chameleon テンプレート を指しています:

<metal:block use-macro="main_template">

  <div metal:fill-slot="content">
    <!-- Main hero unit for a primary marketing message or call to action -->
    ${panel('hero', title='Chameleon')}

    <!-- Example row of columns -->
    <div class="row">
      <p>${panel('headings')}</p>
        <h2>User Info</h2>
        <p>${panel('usermenu',
            user_info={
            'first_name': 'Jane',
            'last_name': 'Doe',
            'username': 'jdoe'}
            )}</p>
    </div>
  </div>

</metal:block>

最初の行はテンプレートを Layout に opt into するものです。 home.jinja2 の中では、この行はこんな風になります:

{% extends main_template %}

これら両方について、 main_template が Pyramid Layout によって Pyramid レンダラーグローバル変数を通してテンプレートのグローバルな名前空間に 挿入されます。その後は、そのテンプレート言語用の通常のセマンティクスに なります。

views.py に戻りましょう。このビュー関数は Layout Manager を 取得しています。 Pyramid Layout は利便性のためにそれを request に格納 しています。 LayoutManager の主な役割は、現在の Layout の 値の get/set です。もちろん、それはこの関数の中で行っていることです。

その後、その関数は Layout インスタンス を取得して グローバルなルックアンドフィールに必要な何らかの状態を操作します。もちろん これは AppLayout クラスでもできたでしょうが、場合によっては別のビューが 見出しに対して異なる値を持っていることがあります。

Panel による再利用可能なスニペット

main template は、その中に興味深いものを持っています:

  <body>

    ${panel('navbar')}

    <div class="container">

      ${next.body()}

      <hr>

      <footer>
        ${panel('footer')}
      </footer>

    </div> <!-- /container -->

    <!-- Le javascript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="${request.static_url('demo:static/js/jquery-1.8.0.min.js')}"></script>
    <script src="${request.static_url('demo:static/js/bootstrap.min.js')}"></script>

  </body>

ここで、グローバルな Layout を Panel によって再利用可能な部分に分解 しています。これらはどこから来たのでしょうか。 @panel_config デコレータです。それは panels.py の中で見ることができます。 例えばこれは:

${panel('navbar')}

...ここから来ています:

@panel_config(
    name='navbar',
    renderer='demo:templates/panels/navbar.mako'
    )
def navbar(context, request):
    def nav_item(name, url):
        active = request.current_route_url() == url
        item = dict(
            name=name,
            url=url,
            active=active
            )
        return item
    nav = [
        nav_item('Mako', request.route_url('home.mako')),
        nav_item('Chameleon', request.route_url('home.chameleon')),
        nav_item('Jinja2', request.route_url('home.jinja2'))
        ]
    return {
        'title': 'Demo App',
        'nav': nav
        }

@panel_config は、 navbar という名前で Panel を登録しました。 その後、テンプレートはそれを使用、 またはオーバーライド することが できます。

home.mako ビューテンプレートにはさらに面白い Panel があります:

${panel('hero', title='Mako')}

...これは以下を呼び出します:

1
2
3
4
5
6
@panel_config(
    name='hero',
    renderer='demo:templates/panels/hero.mako'
    )
def hero(context, request, title='Hello, world!'):
    return {'title': title}

これは、 Panel をパラメータ化して、他の場所で異なる方法で利用 できるということを示しています。

目次

前のトピックへ

Pyramid Layout を使う

次のトピックへ

API Reference