ビューの定義(Defining Views)

A:term:view callablePyramid アプリケーションは通常、 request という単一のパラメータを受け入れる単純なPython関数です。callableビューは response オブジェクトを返すものとします。

リクエストオブジェクトには、 「matchdict」という属性の辞書があります。 「matchdict」 は、一致するURLのプレースホルダ 「pattern」を request URL のパスの部分文字列にマッピングします。たとえば、pyramid.config.Configurator.add_route() への呼び出しに「/{one}/{two}」 というパターンを持ち、ユーザが 「http://example.com/foo/foo/bar」にアクセスするとパタンはと一致します。 「/foo/bar」となり「matchdict」 は 「{'one':'foo', 'two':'bar'}」 のようになります。 。

依存関係「docutils」 の追加( Adding the docutils dependency )

前の章では、新しい依存パッケージ「bcrypt」を追加しました。ここでも、アプリケーションのビューのコードは、オリジナルの 「tutorial」アプリケーションの依存関係ではないパッケージに依存します。

この依存関係を「setup()」関数の「requires」パラメータに割り当てることによって、チュートリアルパッケージの「setup.py」ファイルに「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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import os

from setuptools import setup, find_packages

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

requires = [
    'bcrypt',
    'docutils',
    'plaster_pastedeploy',
    'pyramid >= 1.9a',
    'pyramid_debugtoolbar',
    'pyramid_jinja2',
    'pyramid_retry',
    'pyramid_tm',
    'SQLAlchemy',
    'transaction',
    'zope.sqlalchemy',
    'waitress',
]

tests_require = [
    'WebTest >= 1.3.1',  # py3 compat
    'pytest',
    'pytest-cov',
]

setup(
    name='tutorial',
    version='0.0',
    description='myproj',
    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 pyramid pylons',
    packages=find_packages(),
    include_package_data=True,
    zip_safe=False,
    extras_require={
        'testing': tests_require,
    },
    install_requires=requires,
    entry_points={
        'paste.app_factory': [
            'main = tutorial:main',
        ],
        'console_scripts': [
            'initialize_tutorial_db = tutorial.scripts.initializedb:main',
        ],
    },
)

ハイライト表示された行だけを追加します。

ここでも、前の章で行ったように依存関係をインストールする必要がありますので、「$VENV/bin/pip install -e .」 コマンドを再実行してください。

静的資産(Static assets)

テンプレートには、CSSや画像などの静的資産の名前が付けられます。このファイルはプロジェクトの作成時に提供されるため、パッケージの 「static」ディレクトリ内に作成する必要はありません。

たとえば、「http://localhost:6543/static/theme.css」を経由してCSSファイルにアクセスするには「routes.py」ファイルの「add_static_view」ディレクティブを呼び出してください 。任意の数とタイプの静的アセットをこのディレクトリ(またはサブディレクトリ)に配置できて、単にURLを参照するか、または「static_url」という便利なメソッドを使用するだけです。たとえば「request.static_url('<package>:static/foo.css')」テンプレート内にあります。

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

これは URL Dispatch チュートリアルですので、いくつかのURLパターンをアプリケーションに追加してみましょう。後でURLを処理するビューを添付します。

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

add_route に4回の呼び出しを追加する必要があります。これらの宣言の*順序*は非常に重要であることに注意してください。ルート宣言は、登録された順序で一致します。

  1. / (ルートURLを示す)パターンを view_wiki というルートにマップする宣言を追加してください。次のステップでは、view_wikiビュー・ファンクションに添付された @view_config デコレータによってコール可能な view_wiki ビューにマップします。これは route_name='view_wiki'
  2. /{pagename} パターン を view_page というルートにマップする宣言を追加してください。これはページの通常の表示です。また、次のステップでは、 `` view_page`` ビュー関数にアタッチされた @view_config デコレータによってコール可能な view_page ビューにマップし、 route_name='view_page' です。
  3. /add_page/{pagename} というパターンを add_page というルートにマップする宣言を追加してください。これは、新しいページの追加ビューです。 add_page``ビューにマップされる ``@view_config デコレータは add_page ビュー関数にアタッチされています。これは route_name='add_page' で示されます。
  4. パターン /{pagename}/edit_pageedit_page という名前のルートにマップする宣言を追加してください。これはページの編集ビューです。 edit_page ビュー関数にアタッチされた @view_config デコレータによって呼び出し可能な edit_page ビューにマップします。これは route_name='edit_page' で示されます。 。

編集した結果、routes.py ファイルは次のようになります:

1
2
3
4
5
6
def includeme(config):
    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')

強調表示されている行は、追加または編集が必要な行です。

警告

ルートの順序は重要です! /add_page/{pagename} `` の前に ``/{pagename}/edit_page を置いた場合、ページを追加することはできません。これは、最初のルートが /add_page/edit_page にリクエストを常に一致させるためですが、 /add_page/.. が優先されるようにしたいからです。 wikiページは常にラクダのケースなので、これはこの特定のアプリでは大きな問題ではありませんが、自分のアプリでこの動作を認識することが重要です。

views/default.py にビュー関数を追加する

大きな変化の時です。 `` tutorial/views/default.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
71
72
73
from pyramid.compat import escape
import re
from docutils.core import publish_parts

from pyramid.httpexceptions import (
    HTTPFound,
    HTTPNotFound,
    )

from pyramid.view import view_config

from ..models import Page, User

# 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):
    next_url = request.route_url('view_page', pagename='FrontPage')
    return HTTPFound(location=next_url)

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

    def add_link(match):
        word = match.group(1)
        exists = request.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, escape(word))
        else:
            add_url = request.route_url('add_page', pagename=word)
            return '<a href="%s">%s</a>' % (add_url, escape(word))

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

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

@view_config(route_name='add_page', renderer='../templates/edit.jinja2')
def add_page(request):
    pagename = request.matchdict['pagename']
    if request.dbsession.query(Page).filter_by(name=pagename).count() > 0:
        next_url = request.route_url('edit_page', pagename=pagename)
        return HTTPFound(location=next_url)
    if 'form.submitted' in request.params:
        body = request.params['body']
        page = Page(name=pagename, data=body)
        page.creator = (
            request.dbsession.query(User).filter_by(name='editor').one())
        request.dbsession.add(page)
        next_url = request.route_url('view_page', pagename=pagename)
        return HTTPFound(location=next_url)
    save_url = request.route_url('add_page', pagename=pagename)
    return dict(pagename=pagename, pagedata='', save_url=save_url)

強調表示された行を追加または編集する必要があります。

いくつかのインポートを追加し、WikiWords を見つける正規表現を作成しました。

私たちはもともと alchemy cookiecutterをレンダリングしたときに追加された my_view ビュー関数とそのデコレータを取り除きました。これは単なる例であり、私たちのアプリケーションには関係ありません。 db_err_msg 文字列も削除しました。

前のステップで述べたように、 view/default.py モジュールに view callable 関数を4つ追加しました:

  • view_wiki() - wiki自体を表示します。それはルートURLで答えるでしょう。
  • view_page() - 個々のページを表示します。
  • edit_page() - ユーザがページを編集できるようにします。
  • add_page() - ユーザーがページを追加できるようにします。

以下のセクションでは、それぞれを簡単に説明します。

注釈

ファイル名 default.py がPythonモジュールであることを除いて特別なことは何もありません。プロジェクトは、コードベース全体で、任意の名前付きモジュールで多くのビュー呼び出し可能ファイルを持つことができます。ビュー呼び出し可能関数を実装しているモジュールは、その名前に view をつけている(または、私たちの場合のように `` views`` という名前のアプリケーションパッケージのPythonサブパッケージに入っているかもしれませんが)、これは規約であり、要件ではありません。

`` view_wiki``ビュー関数

以下は `` view_wiki``ビュー関数とそのデコレータのコードです:

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

``view_wiki()``は、wikiのルートURLへのリクエストがあったときに呼び出される default view です。常に FrontPage へのパスを表すURLにリダイレクトされます。

`` view_wiki``ビューcallableは、常に FrontPage という名前のページリソースのURLにリダイレクトします。これを行うには、:class: pyramid.httpexceptions.HTTPFound クラスのインスタンスを返します(インスタンスは :class:pyramid.interfaces.IResponse インターフェイスを実装しています:class:pyramid.response.Response )。これは :meth:pyramid.request.Request.route_url APIを使用して FrontPage ページ(すなわち` http:// localhost:6543/FrontPage` )へのURLを構築し、それをHTTPリダイレクトを形成する `` HTTPFound``応答の&quot;location &quot;を返します。

`` view_page``ビュー関数

`` view_page``ビュー関数とそのデコレータのコードを以下に示します:

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
@view_config(route_name='view_page', renderer='../templates/view.jinja2')
def view_page(request):
    pagename = request.matchdict['pagename']
    page = request.dbsession.query(Page).filter_by(name=pagename).first()
    if page is None:
        raise HTTPNotFound('No such page')

    def add_link(match):
        word = match.group(1)
        exists = request.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, escape(word))
        else:
            add_url = request.route_url('add_page', pagename=word)
            return '<a href="%s">%s</a>' % (add_url, escape(word))

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

`` view_page() ``は、私たちのwikiの1ページを表示するために使われます。これは、ページの:term: reStructuredText`本体( Page``モデルオブジェクトの `data``属性として保存されます)をHTMLとしてレンダリングします。次に、コンパイルされた正規表現を使用して、レンダリングされたHTMLの* WikiWord *参照ごとにHTMLアンカーを置き換えます。

`` add_link``というカルト機能は、 `` wikiwords.sub``の最初の引数として使われ、コンテンツ内の各WikiWordマッチの値を提供するために呼び出されるべきであることを示しています。 wikiに一致するWikiWord名のページがすでに含まれている場合、 `` add_link() ``は置換値として使用されるビューリンクを生成して返します。 wikiに一致するWikiWord名のページがまだ含まれていない場合、 `` add_link() ``は置換値として&quot;add &quot;リンクを生成して返します。

その結果、 `` content``変数は、現在のページオブジェクトの内容に基づいてWikiWords用のさまざまなビューとリンクを含むHTMLの完全に形成されたビットになりました。

テンプレートよりもここでやる方が簡単だから、編集URLを生成し、いくつかの引数を持つ辞書を返します。 `` view_page() ``が辞書(a:term: response`オブジェクトとは対照的に)を返すという事実は、 :app:`Pyramid には:term: renderer`レスポンスを表示するためのビュー構成を使用します。私たちの場合、使用されるレンダラは、 ` view_page() ``に適用される `` @ view_config``デコレータに示されているように、 `` view.jinja2``テンプレートになります。

ページが存在しない場合は、 `` tutorial / views / notfound.py``で定義されている:class: `pyramid.httpexceptions.HTTPNotFound`を404処理をトリガーとして扱う必要があります。

注釈

HTTP例外を使って `` raise``と `` return``を使うことは、一般的に人々を混乱させる重要な違いです。 `` tutorial / views / notfound.py``には、 `` HTTPNotFound``例外を扱うために登録されたterm: exception view`があります。例外ビューは、発生した例外に対してのみトリガされます。 ` HTTPNotFound``が返された場合、内部的な&quot;stock &quot;テンプレートがあり、応答として自身をレンダリングするために使用されます。あなたの例外ビューが実行されているのを見ていない場合、これはおそらく問題です!例外ビューの詳細については、ref: `special_exceptions_in_callables`を参照してください。

`` edit_page``ビュー関数

`` edit_page``ビュー関数とそのデコレータのコードは次のとおりです:

44
45
46
47
48
49
50
51
52
53
54
55
56
@view_config(route_name='edit_page', renderer='../templates/edit.jinja2')
def edit_page(request):
    pagename = request.matchdict['pagename']
    page = request.dbsession.query(Page).filter_by(name=pagename).one()
    if 'form.submitted' in request.params:
        page.data = request.params['body']
        next_url = request.route_url('view_page', pagename=page.name)
        return HTTPFound(location=next_url)
    return dict(
        pagename=page.name,
        pagedata=page.data,
        save_url=request.route_url('edit_page', pagename=page.name),
        )

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

ビューの実行*がフォームの提出の結果である場合(つまり、 `` request.params``の中の `` form.submitted``が `` True``の場合)、ビューは `` body``要素を取得します。リクエストパラメータを設定し、それをページオブジェクトの `` data``属性として設定します。その後、wikiページの `` view_page``ビューにリダイレクトされます。

ビューの実行がフォーム提出の結果でない場合(つまり、 `` request.params``中のform.submittedが `` False``の場合)、ビューは単純に編集フォームをレンダリングし、生成されたフォームのアクションとして使用される `` save_url``があります。

注釈

前章で定義した `` request.dbsession``が `` pyramid_tm``トランザクションマネージャに登録されているので、そのセッションで管理されているオブジェクトに対する変更は自動的にコミットされます。エラーが発生した場合(テンプレートコードでも後で)、変更は中止されます。これは、ビュー自身がコミット/ロールバックロジックに関わる必要はないことを意味します。

`` add_page``ビュー関数

`` add_page``ビュー関数とそのデコレータのコードを以下に示します:

58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
@view_config(route_name='add_page', renderer='../templates/edit.jinja2')
def add_page(request):
    pagename = request.matchdict['pagename']
    if request.dbsession.query(Page).filter_by(name=pagename).count() > 0:
        next_url = request.route_url('edit_page', pagename=pagename)
        return HTTPFound(location=next_url)
    if 'form.submitted' in request.params:
        body = request.params['body']
        page = Page(name=pagename, data=body)
        page.creator = (
            request.dbsession.query(User).filter_by(name='editor').one())
        request.dbsession.add(page)
        next_url = request.route_url('view_page', pagename=pagename)
        return HTTPFound(location=next_url)
    save_url = request.route_url('add_page', pagename=pagename)
    return dict(pagename=pagename, pagedata='', save_url=save_url)

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

`` matchdict``には、追加したいページの名前と一致する `` pagename```キーがあります。 addビューが、例えば `` http:// localhost:6543 / add_page / SomeName``を介して呼び出された場合、 `` matchdict``の `` &#39;pagename```の値は `` SomeName &#39;``。

次に、 `` Page``が既にデータベースに存在するかどうかを判断するためのチェックが行われます。既に存在する場合、クライアントは `` edit_page``ビューにリダイレクトされます。そうでなければ、次のチェックに進みます。

ビューの実行*が*フォームの提出の結果である場合(つまり、 `` request.params``の `` form.submitted &#39;&#39;が `` True``の場合)、フォームデータからページ本文を取得し、createこのページ本文と `` matchdict [&#39;pagename&#39;] ``から取った名前を持つPageオブジェクトを作成し、 `` request.dbession.add``を使ってデータベースに保存します。認証はまだ行っていないので、ページの `` creator``として追加するログインユーザはいません。チュートリアルでその点に達するまでは、すべてのページが `` editor``ユーザによって作成されたと仮定します。したがって、そのオブジェクトをクエリし、 `` page.creator``に設定します。最後に、クライアントを新しく作成したページの `` view_page``ビューにリダイレクトします。

ビューの実行がフォーム提出の結果でない場合(つまり、 `` &#39;form.method&#39; &#39;request.params``が `` False``の場合)、ビューの呼び出し可能ビューはテンプレートをレンダリングします。そのために、テンプレートはレンダリング時にフォームのポストURLとして使用する `` save_url``を生成します。ここでは怠惰なので、追加ビューとページ編集ビューに同じテンプレート( `` templates / edit.jinja2``)を使用します。これを行うために、* pageオブジェクトを `` page``として公開する編集フォームの希望を満たすために、ダミーの `` Page``オブジェクトを作成します。 :app: `Pyramid`は、このビューに関連付けられたテンプレートをレスポンスにレンダリングします。

テンプレートの追加

`` view_page``、 `` add_page``、 `` edit_page``ビューは、参照:a:term: template`を追加しました。各テンプレートは:term: `Jinja2`テンプレートです。これらのテンプレートはチュートリアルパッケージの ` templates``ディレクトリにあります。 Jinja2テンプレートは、そのように認識されるように `` .jinja2``拡張子を持たなければなりません。

`` layout.jinja2``テンプレート

`` tutorial / templates / layout.jinja2``を以下の内容で更新します。

 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
<!DOCTYPE html>
<html lang="{{request.locale_name}}">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="pyramid web application">
    <meta name="author" content="Pylons Project">
    <link rel="shortcut icon" href="{{request.static_url('tutorial:static/pyramid-16x16.png')}}">

    <title>{% block subtitle %}{% endblock %}Pyramid tutorial wiki (based on TurboGears 20-Minute Wiki)</title>

    <!-- Bootstrap core CSS -->
    <link href="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">

    <!-- Custom styles for this scaffold -->
    <link href="{{request.static_url('tutorial:static/theme.css')}}" rel="stylesheet">

    <!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!--[if lt IE 9]>
      <script src="//oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js" integrity="sha384-0s5Pv64cNZJieYFkXYOTId2HMA2Lfb6q2nAcx2n0RTLUnCAoTTsS0nKEO27XyKcY" crossorigin="anonymous"></script>
      <script src="//oss.maxcdn.com/libs/respond.js/1.3.0/respond.min.js" integrity="sha384-f1r2UzjsxZ9T4V1f2zBO/evUqSEOpeaUUZcMTz1Up63bl4ruYnFYeM+BxI4NhyI0" crossorigin="anonymous"></script>
    <![endif]-->
  </head>

  <body>

    <div class="starter-template">
      <div class="container">
        <div class="row">
          <div class="col-md-2">
            <img class="logo img-responsive" src="{{request.static_url('tutorial:static/pyramid.png') }}" alt="pyramid web framework">
          </div>
          <div class="col-md-10">
            <div class="content">
            {% block content %}{% endblock %}
            </div>
          </div>
        </div>
        <div class="row">
          <div class="copyright">
            Copyright &copy; Pylons Project
          </div>
        </div>
      </div>
    </div>


    <!-- Bootstrap core JavaScript
    ================================================== -->
    <!-- Placed at the end of the document so the pages load faster -->
    <script src="//oss.maxcdn.com/libs/jquery/1.10.2/jquery.min.js" integrity="sha384-aBL3Lzi6c9LNDGvpHkZrrm3ZVsIwohDD7CDozL0pk8FwCrfmV7H9w8j3L7ikEv6h" crossorigin="anonymous"></script>
    <script src="//oss.maxcdn.com/libs/twitter-bootstrap/3.0.3/js/bootstrap.min.js" integrity="sha384-s1ITto93iSMDxlp/79qhWHi+LsIi9Gx6yL+cOKDuymvihkfol83TYbLbOw+W/wv4" crossorigin="anonymous"></script>
  </body>
</html>

テンプレートエンジンを使用しているので、ページテンプレートの一般的な定型文を再利用可能なコンポーネントに組み込むことができます。これを行う1つの方法は、ブロックによるテンプレートの継承です。

  • レイアウトテンプレートには、子テンプレートがコンテンツをオーバーライドできる2つのプレースホルダが定義されています。これらのブロックの名前は ``字幕 ``(行11)と ``コンテンツ ``(行36)です。
  • `Jinja2のドキュメントを参照してください<http://jinja.pocoo.org/>テンプレート継承の詳細については `_を参照してください。

`` view.jinja2``テンプレート

`` tutorial / templates / view.jinja2``を作成し、以下の内容を追加してください:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
{% extends 'layout.jinja2' %}

{% block subtitle %}{{page.name}} - {% endblock subtitle %}

{% block content %}
<p>{{ content|safe }}</p>
<p>
<a href="{{ edit_url }}">
    Edit this page
</a>
</p>
<p>
    Viewing <strong>{{page.name}}</strong>, created by <strong>{{page.creator.name}}</strong>.
</p>
<p>You can return to the
<a href="{{request.route_url('view_page', pagename='FrontPage')}}">FrontPage</a>.
</p>
{% endblock content %}

このテンプレートは、単一のwikiページを表示するために `` view_page() ``によって使用されます。

  • 最初に、上記で定義した `layout.jinja2`テンプレートを拡張します。このテンプレートは、ページのスケルトン(行1)を提供します。
  • ページのタイトル(行3)にページ名を挿入して、基本レイアウトから `` subtitle``ブロックをオーバーライドします。
  • 本文にマークアップを挿入するために、基本レイアウトから `` content``ブロックをオーバーライドします(5行目~18行目)。
  • ビューが提供する `` content``値で置き換えられる変数を使用します(6行目)。 `` content``はHTMLを含んでいるので、 `` safe``フィルタはエスケープするのを防ぐために使われます(例えば、&quot;&gt; &quot;を&quot;&gt; &quot;に変更する)。
  • クリックすると、要求されたページの `` edit_page``ビューが呼び出されます(8-10行目)。

`` edit.jinja2``テンプレート

`` tutorial / templates / edit.jinja2``を作成し、以下の内容を追加してください:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
{% extends 'layout.jinja2' %}

{% block subtitle %}Edit {{pagename}} - {% endblock subtitle %}

{% block content %}
<p>
Editing <strong>{{pagename}}</strong>
</p>
<p>You can return to the
<a href="{{request.route_url('view_page', pagename='FrontPage')}}">FrontPage</a>.
</p>
<form action="{{ save_url }}" method="post">
<div class="form-group">
    <textarea class="form-control" name="body" rows="10" cols="60">{{ pagedata }}</textarea>
</div>
<div class="form-group">
    <button type="submit" name="form.submitted" value="Save" class="btn btn-default">Save</button>
</div>
</form>
{% endblock content %}

このテンプレートは2つのユースケースを扱います。これは `` add_page() ``と `` edit_page() ``によってwikiページの追加と編集に使用されます。フォームを含むページが表示され、次の情報が表示されます。

  • ここでもまた、ページのスケルトン(1行目)を提供する `layout.jinja2`テンプレートを拡張します。
  • <html> `` subtitle``ブロックをオーバーライドして、 `` <title> ``タグ ``の `` head``(行3)にある。&lt;/ html&gt;
  • 既存のページデータがレンダリングされたときにそれが埋め込まれた body`という名前の10行×60列の textarea`フィールドです(14行目)。
  • 「form.submitted」という名前の送信ボタン(17行目)。
  • フォームは、ビューが提供する `` save_url``引数に戻ります(12行目)。ビューは `` body``と `` form.submitted``の値を使用します。

`` 404.jinja2``テンプレート

`` tutorial / templates / 404.jinja2``を以下の内容に置き換えてください:

1
2
3
4
5
6
7
8
{% extends "layout.jinja2" %}

{% block content %}
<div class="content">
  <h1><span class="font-semi-bold">Pyramid tutorial wiki</span> <span class="smaller">(based on TurboGears 20-Minute Wiki)</span></h1>
  <p class="lead"><span class="font-semi-bold">404</span> Page Not Found</p>
</div>
{% endblock content %}

このテンプレートは、以下に示すように `` tutorial / views / notfound.py``で定義された `` notfound_view``からリンクされています:

1
2
3
4
5
6
7
from pyramid.view import notfound_view_config


@notfound_view_config(renderer='../templates/404.jinja2')
def notfound_view(request):
    request.response.status = 404
    return {}

この設定については、いくつか重要な点があります。

  • 上のsnippetの `` notfound_view``は:term: `例外ビュー`と呼ばれます。詳細については、ref: `special_exceptions_in_callables`を参照してください。
  • `` notfound_view``はレスポンスステータスを404に設定します:ref: `request_response_attr`でレンダラが使用するレスポンスオブジェクトに影響を与えることができます。
  • `` notfound_view``は例外ビューとして登録され、 `` pyramid.httpexceptions.HTTPNotFound``が例外として呼び出された場合に** **のみ呼び出されます。つまり、通常はビューから返された応答に対しては呼び出されません。たとえば、 `` tutorial / views / default.py`の27行目では、ビューがトリガされる例外が発生します。

最後に、 `` alchemy`` cookiecutterによって提供された `` tutorial / templates / mytemplate.jinja2``テンプレートを削除するかもしれません。これはwiki用の独自のテンプレートを作成したからです。

注釈

私たちのテンプレートは、私たちのチュートリアルビューのどれもが辞書に返されない `` request``オブジェクトを使います。 `` request``は、テンプレートレンダラーが使用されているときに、テンプレート内でデフォルトで利用可能ないくつかの名前の1つです。テンプレートがレンダラーとして使われるときにデフォルトで利用可能な他の名前については、ref: `renderer_system_values`を参照してください。

ブラウザでのアプリケーションの表示

ブラウザでアプリケーションを調べることができます(ref: `wiki2-start-the-application`を参照してください)。ブラウザを起動し、次の各URLにアクセスして、結果が期待どおりであることを確認します。

  • http:// localhost:6543 / `` view_wiki``ビューを呼び出します。これは常に `` FrontPage``ページオブジェクトの `` view_page``ビューにリダイレクトされます。
  • http:// localhost:6543 / FrontPageは `` FrontPage``ページオブジェクトの `` view_page``ビューを呼び出します。
  • http:// localhost:6543 / FrontPage / edit_pageは、 `` FrontPage``ページオブジェクトの `` edit_page``ビューを呼び出します。
  • http:// localhost:6543 / add_page / SomePageNameはページの `` add_page``ビューを呼び出します。ページがすでに存在する場合は、ページオブジェクトの `` edit_page``ビューにユーザをリダイレクトします。
  • http://localhost:6543/SomePageName/edit_page は、既存のページの edit_page ビューを呼び出し、ページが存在しない場合はエラーを生成します。
  • エラーを生成するには、 http://localhost:6543/foobars/edit_page にアクセスし、 NoResultFound: No row was found for one() エラーで行が見つかりませんでした。対話的なトレースバック機能がterm: `pyramid_debugtoolbar`によって提供されます。