ビューを定義する

Pyramid アプリケーションにおける view callable は、 典型的には request という名前の 1 つのパラメータを受け取るシンプル な Python 関数です。ビュー callable は response オブジェクトを返す ことが想定されます。

ルートマッチの結果として呼び出される全てのビューに渡される request オブ ジェクトは、 route 文の パターン によって URL に placed into された 要素が格納されている matchdict という名前の属性を持っています。 例えば、 __init__.py の中で行っている pyramid.config.Configurator.add_route() の呼び出しに {one}/{two} というパターンがあり、 http://example.com/foo/bar という URL が呼び出された場合、このパターンにマッチして、 'foo' という 値が 'one' というキーに、 'bar' という値が 'two' というキーに 割り当てられた matchdict という辞書が request に付け加えられてビューに 渡されます。

このチュートリアルステージのソースコードを以下の場所で閲覧することができます。 http://github.com/Pylons/pyramid/tree/1.3-branch/docs/tutorials/wiki2/src/views/.

setup.py ファイルに依存関係を宣言する

私たちのアプリケーションのビューのコードはオリジナルの “tutorial” アプリケーションの依存関係にはないパッケージに依存しています。オリジナルの “tutorial” アプリケーションは pcreate によって生成され、私たちの カスタムアプリケーションに必要なものを知りません。

tutorial パッケージの setup.py ファイルでこの依存関係を setup 関数内の requires パラメータに割り当てることによって docutils パッケージへの依存を追加する必要があります。

tutorial/setup.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
45
import os

from setuptools import setup, find_packages

here = os.path.abspath(os.path.dirname(__file__))
README = open(os.path.join(here, 'README.txt')).read()
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()

requires = [
    'pyramid',
    'SQLAlchemy',
    'transaction',
    'pyramid_tm',
    'pyramid_debugtoolbar',
    'zope.sqlalchemy',
    'waitress',
    'docutils',
    ]

setup(name='tutorial',
      version='0.0',
      description='tutorial',
      long_description=README + '\n\n' + CHANGES,
      classifiers=[
        "Programming Language :: Python",
        "Framework :: Pyramid",
        "Topic :: Internet :: WWW/HTTP",
        "Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
        ],
      author='',
      author_email='',
      url='',
      keywords='web wsgi bfg pylons pyramid',
      packages=find_packages(),
      include_package_data=True,
      zip_safe=False,
      test_suite='tutorial',
      install_requires=requires,
      entry_points="""\
      [paste.app_factory]
      main = tutorial:main
      [console_scripts]
      initialize_tutorial_db = tutorial.scripts.initializedb:main
      """,
      )

(ハイライトされた行は変更が必要な箇所です)

setup.py develop を実行する

新しいソフトウェア依存関係が追加されたので、新たに追加された依存パッケージ を登録および取得するために tutorial パッケージのルート内で python setup.py develop を再実行する必要があります。

現在のワーキングディレクトリがプロジェクトのルート (seetup.py のある ディレクトリ) であることを確認して、次のコマンドを実行してください:

UNIX の場合:

$ cd tutorial
$ ../bin/python setup.py develop

Windows の場合:

c:\pyramidtut> cd tutorial
c:\pyramidtut\tutorial> ..\Scripts\python setup.py develop

このコマンドの実行に成功すると、コンソールに次のような出力が行われるでしょう:

Finished processing dependencies for tutorial==0.0

views.py ファイルを変更する

大幅な変更をするときが来ました。 tutorial/tutorial/views.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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import re
from docutils.core import publish_parts

from pyramid.httpexceptions import (
    HTTPFound,
    HTTPNotFound,
    )
from pyramid.view import view_config

from .models import (
    DBSession,
    Page,
    )

# regular expression used to find WikiWords
wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")

@view_config(route_name='view_wiki')
def view_wiki(request):
    return HTTPFound(location = request.route_url('view_page',
                                                  pagename='FrontPage'))

@view_config(route_name='view_page', renderer='templates/view.pt')
def view_page(request):
    pagename = request.matchdict['pagename']
    page = DBSession.query(Page).filter_by(name=pagename).first()
    if page is None:
        return HTTPNotFound('No such page')

    def check(match):
        word = match.group(1)
        exists = DBSession.query(Page).filter_by(name=word).all()
        if exists:
            view_url = request.route_url('view_page', pagename=word)
            return '<a href="%s">%s</a>' % (view_url, word)
        else:
            add_url = request.route_url('add_page', pagename=word)
            return '<a href="%s">%s</a>' % (add_url, word)

    content = publish_parts(page.data, writer_name='html')['html_body']
    content = wikiwords.sub(check, content)
    edit_url = request.route_url('edit_page', pagename=pagename)
    return dict(page=page, content=content, edit_url=edit_url)

@view_config(route_name='add_page', renderer='templates/edit.pt')
def add_page(request):
    pagename = request.matchdict['pagename']
    if 'form.submitted' in request.params:
        body = request.params['body']
        page = Page(pagename, body)
        DBSession.add(page)
        return HTTPFound(location = request.route_url('view_page',
                                                      pagename=pagename))
    save_url = request.route_url('add_page', pagename=pagename)
    page = Page('', '')
    return dict(page=page, save_url=save_url)

@view_config(route_name='edit_page', renderer='templates/edit.pt')
def edit_page(request):
    pagename = request.matchdict['pagename']
    page = DBSession.query(Page).filter_by(name=pagename).one()
    if 'form.submitted' in request.params:
        page.data = request.params['body']
        DBSession.add(page)
        return HTTPFound(location = request.route_url('view_page',
                                                      pagename=pagename))
    return dict(
        page=page,
        save_url = request.route_url('edit_page', pagename=pagename),
        )

(ハイライトされた行は変更が必要な箇所です)

alchemy scaffold を使ってプロジェクトを生成した時に加えられた my_view ビュー関数とそのデコレータを取り除きました。それは単なる 例で、このアプリケーションには適切ではありません。

そして、 views.py モジュールに4つの view callable 関数を 追加しました:

  • view_wiki() - wiki 自体を表示します。それはルート URL の上で答えます。
  • view_page() - 個々のページを表示します。
  • add_page() - ページの追加を可能にします。
  • edit_page() - ページの編集を可能にします。

各々について簡潔に記述し、結果の views.py ファイルを後で示します。

Note

views.py というファイル名に特別な意味はありません。プロジェクト はそのコードベース全体で任意の名前のファイル中に多くのビューを持つこ とができます。ビューを実装するファイルは多くの場合 view というファ イル名を持っています (もしくは views という名前の アプリケーショ ンパッケージの中の Python サブパッケージに存在しています) が、これは 単なる慣例です。

ビュー関数 view_wiki

view_wiki() は wiki のルート URL に対してリクエストが行われたときに 呼び出される default view です。それは常に “FrontPage” へのパス を表す URL にリダイレクトします。

1
2
3
4
@view_config(route_name='view_wiki')
def view_wiki(request):
    return HTTPFound(location = request.route_url('view_page',
                                                  pagename='FrontPage'))

view_wiki()pyramid.httpexceptions.HTTPFound クラスの インスタンスを返します (それは pyramid.response.Response のように pyramid.interfaces.IResponse インターフェースを実装した インスタンスです) 。

それは FrontPage ページの URL (例えば http://localhost:6543/FrontPage) を構築するために pyramid.request.Request.route_url() APIを使用します。そして、 それを HTTPFound レスポンスの “location” として使用し、 HTTP リダイレクト を生成します。

ビュー関数 view_page

view_page() は wiki の単一のページを表示するために使用されます。 それは (Page モデルオブジェクトの data 属性として保存された) ReStructuredText で書かれたページの内容を HTML としてレンダリング します。その後、コンパイル済み正規表現を使用して、レンダリング済み HTML 中の各 WikiWord 参照を HTML アンカーに置換します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
@view_config(route_name='view_page', renderer='templates/view.pt')
def view_page(request):
    pagename = request.matchdict['pagename']
    page = DBSession.query(Page).filter_by(name=pagename).first()
    if page is None:
        return HTTPNotFound('No such page')

    def check(match):
        word = match.group(1)
        exists = DBSession.query(Page).filter_by(name=word).all()
        if exists:
            view_url = request.route_url('view_page', pagename=word)
            return '<a href="%s">%s</a>' % (view_url, word)
        else:
            add_url = request.route_url('add_page', pagename=word)
            return '<a href="%s">%s</a>' % (add_url, word)

    content = publish_parts(page.data, writer_name='html')['html_body']
    content = wikiwords.sub(check, content)
    edit_url = request.route_url('edit_page', pagename=pagename)
    return dict(page=page, content=content, edit_url=edit_url)

check() 関数は wikiwords.sub の最初の引数として使用されます。 それはコンテンツ内で見つかった各 WikiWord のマッチに対して値を提供するために 呼び出す必要があると指示しています。もし、マッチした WikiWord 名を持つ ページが wiki にすでに含まれている場合、 check() は置換する値として view リンクを生成してそれを返します。もし、マッチした WikiWord 名を持つ ページがまだ wiki に含まれていない場合、関数は置換する値として “add” リンクを生成してそれを返します。

この結果、 content 変数は現在のページオブジェクトの内容に基づいて WikiWord への様々な view または add リンクを含む完全な HTML 形式に なっています。

その後、 edit URL を生成し (テンプレートの中よりもここで行うほうが簡単だ からです)、いくつかの引数を含む辞書を返します。このビューが (response オブジェクトではなく) 辞書を返すという事実は、 テンプレートをレンダリングするためにビュー設定で関連付けられた renderer を使用する必要があることを Pyramid に知らせます。 この場合、レンダリングされるテンプレートは view_page() に適用された @view_config デコレータが示すように templates/view.pt テンプレート になります。

ビュー関数 add_page

add_page() は、まだシステム内のページとして表されていない WikiWord をユーザがクリックしたときに呼び出されます。 view_page ビュー内の check 関数がこのビューへの URL を生成します。 add_page はまた、ページオブジェクトを追加するときに生成される フォームのハンドラとして機能します。 add_page() ビューに渡される リクエストの matchdict 属性は、 URL の構築とモデルオブジェクトの 検索に必要な値を含んでいます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
@view_config(route_name='add_page', renderer='templates/edit.pt')
def add_page(request):
    pagename = request.matchdict['pagename']
    if 'form.submitted' in request.params:
        body = request.params['body']
        page = Page(pagename, body)
        DBSession.add(page)
        return HTTPFound(location = request.route_url('view_page',
                                                      pagename=pagename))
    save_url = request.route_url('add_page', pagename=pagename)
    page = Page('', '')
    return dict(page=page, save_url=save_url)

matchdict は追加したいページの名前に一致する 'pagename' キーを 持つことになります。もし、 add ビューが例えば http://localhost:6543/add_page/SomeName 経由で呼び出された場合、 matchdict の中の 'pagename' の値は 'SomeName' になります。

ビューの実行がフォーム送信の結果で ある 場合 (つまり評価式 'form.submitted' in request.paramsTrue の場合)、 フォームデータからページの本体を取り出し、このページの本体と matchdict['pagename'] から取り出した名前から Page オブジェクトを 生成し、 DBSession.add を使ってそれをデータベースに保存します。 その後、新しく作成したページの view_page ビューにリダイレクトします。

ビューの実行がフォーム送信の結果では ない 場合 (つまり評価式 'form.submitted' in request.paramsFalse の場合) 、ビュー callable はテンプレートをレンダリングします。そのために、テンプレート のレンダリング時にフォームのポスト URL として使用される “save url” を 生成します。ここでは手を抜いて、同じテンプレート (templates/edit.pt) を追加ビューだけでなく、ページ編集ビューに使用することにします。 page として公開される なんらかの ページオブジェクトを持っていると いう編集フォームの要求を満たすために、ダミー Page オブジェクトを生成します。 そして、 Pyramid はレスポンスとしてこのビューに関連付けられている テンプレートをレンダリングします。

ビュー関数 edit_page

edit_page() は、ユーザーが view フォームの “Edit this Page” ボタン をクリックしたときに呼び出されます。 edit_page は編集フォームを レンダリングしますが、レンダリングしたフォームのハンドラとしても機能します。 edit_page ビューに渡されるリクエストの matchdict 属性は、ユーザー が編集するページの名前に一致する 'pagename' キーを持つことになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
@view_config(route_name='edit_page', renderer='templates/edit.pt')
def edit_page(request):
    pagename = request.matchdict['pagename']
    page = DBSession.query(Page).filter_by(name=pagename).one()
    if 'form.submitted' in request.params:
        page.data = request.params['body']
        DBSession.add(page)
        return HTTPFound(location = request.route_url('view_page',
                                                      pagename=pagename))
    return dict(
        page=page,
        save_url = request.route_url('edit_page', pagename=pagename),
        )

ビューの実行がフォーム送信の結果で ある 場合 (つまり評価式 'form.submitted' in request.paramsTrue の場合)、 リクエストパラメータの body 要素を取得し、 page オブジェクトの data 属性としてセットします。次に wiki ページの view_page ビューにリダイレクトします。

ビューの実行がフォーム送信の結果では ない 場合 (つまり評価式 'form.submitted' in request.paramsFalse の場合)、 page オブジェクトと、生成されたフォームのアクションとして使用するための save_url を渡して単に編集フォームをレンダリングします。

テンプレートの追加

追加した view_page, add_page, edit_page ビューは template を参照しています。各テンプレートは Chameleon ZPT テンプレートです。これらのテンプレートは tutorial パッケージの templates ディレクトリの中にあります。 Chameleon テンプレートとして 認識されるためには .pt 拡張子を持たなければなりません。

view.pt テンプレート

tutorial/tutorial/templates/view.pt を作成して次の内容を追加してください:

 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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
  <title>${page.name} - Pyramid tutorial wiki (based on
    TurboGears 20-Minute Wiki)</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="python web application" />
  <meta name="description" content="pyramid web application" />
  <link rel="shortcut icon"
        href="${request.static_url('tutorial:static/favicon.ico')}" />
  <link rel="stylesheet"
        href="${request.static_url('tutorial:static/pylons.css')}"
        type="text/css" media="screen" charset="utf-8" />
  <!--[if lte IE 6]>
  <link rel="stylesheet"
        href="${request.static_url('tutorial:static/ie6.css')}"
        type="text/css" media="screen" charset="utf-8" />
  <![endif]-->
</head>
<body>
  <div id="wrap">
    <div id="top-small">
      <div class="top-small align-center">
        <div>
          <img width="220" height="50" alt="pyramid"
        src="${request.static_url('tutorial:static/pyramid-small.png')}" />
        </div>
      </div>
    </div>
    <div id="middle">
      <div class="middle align-right">
        <div id="left" class="app-welcome align-left">
          Viewing <b><span tal:replace="page.name">Page Name
              Goes Here</span></b><br/>
          You can return to the
          <a href="${request.application_url}">FrontPage</a>.<br/>
        </div>
        <div id="right" class="app-welcome align-right"></div>
      </div>
    </div>
    <div id="bottom">
      <div class="bottom">
        <div tal:replace="structure content">
          Page text goes here.
        </div>
        <p>
          <a tal:attributes="href edit_url" href="">
            Edit this page
          </a>
        </p>
      </div>
    </div>
  </div>
  <div id="footer">
    <div class="footer"
         >&copy; Copyright 2008-2011, Agendaless Consulting.</div>
  </div>
</body>
</html>

このテンプレートは、単一の wiki ページを表示するために view_page() によって使用されます。以下の内容が含まれています:

  • ビューによって提供される content 値で置き換えられる div 要素 (45-47行目)。 content には HTML が含まれます。そのためエスケープ (つまり “>” を “&gt;” にするような変更) を防ぐために structure キーワードが使われています。
  • 表示されているページに対して edit_page ビューを呼び出す “edit” URL を指すリンク (49-51行目)。

edit.pt テンプレート

tutorial/tutorial/templates/edit.pt を作成して次の内容を追加してください:

 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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
      xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
  <title>${page.name} - Pyramid tutorial wiki (based on
    TurboGears 20-Minute Wiki)</title>
  <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
  <meta name="keywords" content="python web application" />
  <meta name="description" content="pyramid web application" />
  <link rel="shortcut icon"
        href="${request.static_url('tutorial:static/favicon.ico')}" />
  <link rel="stylesheet"
        href="${request.static_url('tutorial:static/pylons.css')}"
        type="text/css" media="screen" charset="utf-8" />
  <!--[if lte IE 6]>
  <link rel="stylesheet"
        href="${request.static_url('tutorial:static/ie6.css')}"
        type="text/css" media="screen" charset="utf-8" />
  <![endif]-->
</head>
<body>
  <div id="wrap">
    <div id="top-small">
      <div class="top-small align-center">
        <div>
          <img width="220" height="50" alt="pyramid"
        src="${request.static_url('tutorial:static/pyramid-small.png')}" />
        </div>
      </div>
    </div>
    <div id="middle">
      <div class="middle align-right">
        <div id="left" class="app-welcome align-left">
          Editing <b><span tal:replace="page.name">Page Name Goes
            Here</span></b><br/>
          You can return to the
          <a href="${request.application_url}">FrontPage</a>.<br/>
        </div>
        <div id="right" class="app-welcome align-right"></div>
      </div>
    </div>
    <div id="bottom">
      <div class="bottom">
        <form action="${save_url}" method="post">
          <textarea name="body" tal:content="page.data" rows="10"
                    cols="60"/><br/>
          <input type="submit" name="form.submitted" value="Save"/>
        </form>
      </div>
    </div>
  </div>
  <div id="footer">
    <div class="footer"
         >&copy; Copyright 2008-2011, Agendaless Consulting.</div>
  </div>
</body>
</html>

このテンプレートは wiki ページの追加と編集のために add_page()edit_page() によって使用されます。これは以下のようなフォームを含む ページを表示します。

  • レンダリングされた時に既存のページのデータで埋められる、 10列60行の “body” という名前の textarea フィールド (46-47行目)。
  • “form.submitted” という名前の送信ボタン (48行目)。

このフォームは、ビューによって提供される “save_url” 引数に POST 送信されます (45行目)。ビューは bodyform.submitted の値を使います。

Note

これらのテンプレートでは、いずれのビューでもその辞書の中で返していない request オブジェクトを利用しています。 request はテンプレート内で “デフォルトで” 利用可能ないくつかの名前のうちの1つです。レンダラーとして Chameleon テンプレートを使用しているときにテンプレート内でデフォルトで 利用可能な他の名前についての情報は *.pt または *.txt: Chameleon テンプレートレンダラー を参照してください。

静的アセット

これらのテンプレートは pylons.css という名前の静的アセットを 参照しています。このファイルはプロジェクトを作成した時点で提供されているので、 パッケージの static ディレクトリ内にこのファイルを作成する必要は ありません。このファイルはこのガイドの本体内で置き換えるには少し長すぎますが、 オンライン. で 利用可能です。

この CSS ファイルは __init__.py ファイルの中で行なった add_static_view の宣言の呼び出しのために、例えば http://localhost:6543/static/pylons.css を介してアクセスされます。 任意の数と種類の静的アセットはこのディレクトリ (またはサブディレクトリ) に配置することができ、 URL によって参照するか、便利なメソッド static_url を使用して参照します。例えばテンプレート内で request.static_url('{{package}}:static/foo.css') のように使用します。

__init__.py にルートを追加する

__init__.py ファイルにはアプリケーションにルートを追加するための pyramid.config.Configurator.add_route() の呼び出しが含まれています。 最初に、テンプレート (訳注: scaffold) によって作成された 'home' という 名前を使用している既存のルートを取り除きます。これは単なる例で、この アプリケーションには関係ありません。

その後、 add_route を4回呼び出す必要があります。なお、これらの宣言 の 順番 は非常に重要です。 ルート 宣言はそれらが __init__.py ファイルの中で見つかった順番でマッチされます。

  1. / というパターン (ルート URL の意味) から view_wiki という名前の ルートにマッピングする宣言を追加します。それは view_wiki ビュー 関数に付けられた route_name='view_wiki' を示す @view_config に よって、ビュー callable view_wiki にマッピングします。
  1. /{pagename} というパターンを view_page という名前のルートに マッピングする宣言を追加します。これはページに対する通常のビューです。 それは view_page ビュー関数に付けられた route_name='view_page' を示す @view_config によって、ビュー callable view_page にマッピングします。
  1. /add_page/{pagename} というパターンを add_page という名前の ルートにマッピングする宣言を追加します。これは新しいページを追加する ためのビューです。それは add_page ビュー関数に付けられた route_name='add_page' を示す @view_config によって、ビュー callable add_page にマッピングします。
  1. /{pagename}/edit_page というパターンを edit_page という名前の ルートにマッピングする宣言を追加します。これはページの編集ビューです。 それは edit_page ビュー関数に付けられた route_name='edit_page' を示す @view_config によって、ビュー callable edit_page にマッピングします。

編集の結果として __init__.py ファイルはこのようになるはずです:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pyramid.config import Configurator
from sqlalchemy import engine_from_config

from .models import (
    DBSession,
    Base,
    )


def main(global_config, **settings):
    """ This function returns a Pyramid WSGI application.
    """
    engine = engine_from_config(settings, 'sqlalchemy.')
    DBSession.configure(bind=engine)
    Base.metadata.bind = engine
    config = Configurator(settings=settings)
    config.add_static_view('static', 'static', cache_max_age=3600)
    config.add_route('view_wiki', '/')
    config.add_route('view_page', '/{pagename}')
    config.add_route('add_page', '/add_page/{pagename}')
    config.add_route('edit_page', '/{pagename}/edit_page')
    config.scan()
    return config.make_wsgi_app()

(ハイライトされた行は変更が必要な箇所です)

ブラウザでアプリケーションを表示する

ようやくブラウザでアプリケーションを実行することができます (アプリケーションの起動 参照) 。ブラウザを起動して次の 各 URL を開き、結果が予想通りであることをチェックしてください:

  • http://localhost:6543 にブラウザでアクセスすると view_wiki ビューが呼び出されます。このビューは常に FrontPage page オブジェクトの view_page ビューにリダイレクトします。
  • http://localhost:6543/FrontPage にブラウザでアクセスすると、 フロントページオブジェクトの view_page ビューが呼び出されます。
  • http://localhost:6543/FrontPage/edit_page にブラウザでアクセス すると、フロントページ page オブジェクトの edit ビューが呼び出されます。
  • http://localhost:6543/add_page/SomePageName にブラウザでアクセス すると、ページの add ビューが呼び出されます。
  • エラーを発生させるために http://localhost:6543/foobars/edit_page に アクセスしてください。それは NoResultFound: No row was found for one() エラーを発生させます。 pyramid_debugtoolbar によって提供された インタラクティブトレースバック機能が見られるでしょう。