ビュー

Pyramid の重要な仕事のうちの一つは、 request が アプリケーションに達したときに view callable を見つけて起動する ことです。ビュー callable は、あなたのアプリケーションになされたリクエスト に応じて興味深いことを行うコードの断片です。それらはあらゆる面白いウェブ アプリケーションの「肉(本質、芯)」です。

Note

Pyramid view callable は、会話での省略表現でしばしば view と呼ばれます。しかし、ビュー 設定 とビュー callable を実装するコード、およびビュー 検索 プロセスの間に著しい違いがあるので、 このドキュメンテーションでは、それほど曖昧でない用語を使用する必要が あります。

本章では、ビュー callable をどのように定義するかを説明します。実際に どのようにして特定の URL パターンおよび他のリクエスト状況に対してビュー callable を接続するように Pyramid に伝えるかを理解するためには、 次章 (View Configuration) まで待たなければなりません。

ビュー callable

ビュー callable は、自明のことのように聞こえる危険を冒せば、 callable な Python オブジェクトです。具体的には、ビュー callable は、関数、クラス、または __call__ メソッド (これによりインスタンスが呼び出し可能になります) を 実装したインスタンスです。

ビュー callable は、最低限 request という名前の単一の引数を受け取る 必要があります。この引数は Pyramid Request オブジェクトを 表わします。 request オブジェクトは、上流の WSGI サーバーによって Pyramid に提供される WSGI 環境変数を表わします。 予想されるように、 request オブジェクトは実行中の特定の HTTP リクエストに 関してアプリケーションが知る必要のあるすべてのものを含んでいます。

ビュー callable の最終責任は Pyramid Response オブジェクト を生成することです。これは、ビュー callable コード内で Response オブジェクトを生成してそれを直接返すか、あるいはビュー callable の本体 内部から特別な種類の例外を上げることによって行うことができます。

ビュー callable を関数として定義する

ビュー callable を定義する最も簡単な方法のうちの一つは、 request という名前の単一の引数を受け取り、 Response オブジェクトを返す 関数を作成することです。例えば、これは関数として実装された “hello world” ビュー callable です:

1
2
3
4
from pyramid.response import Response

def hello_world(request):
    return Response('Hello world!')

ビュー callable をクラスとして定義する

ビュー callable は関数の代わりに Python クラスによっても表すことができます。 ビュー callable がクラスである場合、それが関数または別の非クラスの callable である場合とは呼び出しのセマンティクスがやや異なります。ビュー callable がクラスである場合、クラスの __init__ メソッドが request パラメータ を伴って呼ばれます。その結果、クラスのインスタンスが生成されます。続いて、 そのインスタンスの __call__ メソッドがパラメータなしで起動されます。 クラスとして定義されたビューには次のような特性がなければなりません:

  • request 引数を受け取る __init__ メソッド。
  • パラメータを受け取らず、レスポンスを返す __call__ (あるいは他の) メソッド。

例えば:

1
2
3
4
5
6
7
8
from pyramid.response import Response

class MyView(object):
    def __init__(self, request):
        self.request = request

    def __call__(self):
        return Response('hello')

__init__ に渡された request オブジェクトは ビュー callable を関数として定義する で述べたのと同じ型の request オブジェクトです。

レスポンスを返すことが期待されるメソッドを表わすために __call__ と は別の属性を使用したければ、ビュー設定の一部として attr 値を使用する ことができます。 View Configuration Parameters を参照してください。 クラスが関連するビュー callable のコレクションを表わすようにしたければ、 各々クラスの異なるメソッドを指す異なる attr 値を用いて、同じビュー callable クラスを異なるビュー設定の中で使用することができます。

ビュー callable レスポンス

ビュー callable は、 Pyramid Response インタフェースを 実装するオブジェクトを返すことができます。 Response インタフェース を実装するものを返す最も簡単な方法は、 pyramid.response.Response オブジェクトのインスタンスを直接 返すことです。例えば:

1
2
3
4
from pyramid.response import Response

def view(request):
    return Response('OK')

Pyramid は、 pyramid.response.Response を継承する一連の 様々な「例外」クラスを提供しています。例えば、クラス pyramid.httpexceptions.HTTPFound のインスタンスは Response を継承するので、これも有効な response オブジェクトです。例については、 HTTP 例外HTTP リダイレクトを行うためにビュー callable を使う を参照してください。

Note

様々な状況で pyramid.response.Response のインスタンスでない オブジェクトをビュー callable から返すこともできます。 これはテストを書くときや複数のビュー callable の間でコードを共有しようと するときに有用なことがあります。これを可能にする通常の方法については レンダラー を参照してください。それよりもまれな、 ビュー callable が Response オブジェクト以外を返すことを可能にする方法は Pyramid がビューレスポンスを扱う方法の変更 の中で文書化されます。

ビュー callable の中で特別な例外を使用する

通常、ビュー callable 内で Python 例外が上がった場合、 Pyramid は アプリケーションを起動した WSGI サーバまで例外が伝搬することを 許します。例外は通常そこで捕捉されてログに記録されます。

しかし、利便性のために特別な例外のセットが存在しています。これらの例外が ビュー callable 内で上がった場合、 Pyramid によって常にレスポンスが 生成されます。これらは HTTP exception オブジェクトとして知られています。

HTTP 例外

pyramid.httpexceptions モジュールの中で pyramid.httpexceptions.HTTPException から継承すると文書化 されたすべてのクラスは http exception オブジェクトです。 HTTP 例外オブジェクトのインスタンスは、ビューコードの内部から 戻り値として返される か、または 例外として投げられ ます。 いずれの場合も、そのインスタンスはビューからのレスポンスとして 使用されます。

例えば、 pyramid.httpexceptions.HTTPUnauthorized 例外を投げる ことができます。これは 401 Unauthorized ステータスでレスポンスを生成 するでしょう:

1
2
3
4
from pyramid.httpexceptions import HTTPUnauthorized

def aview(request):
    raise HTTPUnauthorized()

HTTP 例外は raise する代わりに 返す こともできます (HTTP 例外は有効な response オブジェクトでもあります):

1
2
3
4
from pyramid.httpexceptions import HTTPUnauthorized

def aview(request):
    return HTTPUnauthorized()

HTTP 例外を生成するための近道は pyramid.httpexceptions.exception_response() 関数です。この関数は、 HTTP ステータスコードを受け取り対応する HTTP 例外を返します。例えば、 HTTPUnauthorized をインポートして response オブジェクトを構築する代わりに、同じオブジェクトを構築して返す ために exception_response() 関数を使用する ことができます。

1
2
3
4
from pyramid.httpexceptions import exception_response

def aview(request):
    raise exception_response(401)

これは 401 が “HTTP Unauthorized” のための HTTP ステータスコードであるためです。 したがって、 raise exception_response(401)raise HTTPUnauthorized() と機能的に等価です。 pyramid.httpexceptions の中で、各 HTTP レスポンスコードから その目的および関連する HTTP 例外オブジェクトにマッピングする ドキュメンテーションが提供されます。

Note

exception_response() 関数は Pyramid 1.1 で新たに追加されました。

Pyramid は HTTP 例外をどのように使用するか

HTTP 例外はアプリケーション開発者が直接使うためのものです。 しかし、 Pyramid は自身も通常動作の間に様々なポイントで 2 つの HTTP 例外を上げます: pyramid.httpexceptions.HTTPNotFoundpyramid.httpexceptions.HTTPForbidden です。 リクエストをサービスするビューが見つからない場合、 Pyramid は HTTPNotFound 例外を上げます。 認可がセキュリティポリシーによって禁止された場合、 Pyramid は Forbidden 例外を上げます。

HTTPNotFound が Pyramid 自体によって、 またはビューコード内で上げられる場合、 Not Found View の結果が リクエストを行なったユーザエージェントに返されます。

HTTPForbidden が Pyramid 自体によって、 またはビューコード内で上げられる場合、 Forbidden View の結果が リクエストを行なったユーザエージェントに返されます。

カスタム例外ビュー

ビュー callable の中で特別な例外を使用する に述べられているように、 HTTP 例外が投げられて専用のビューによって補足されることを可能にする機構を、 アプリケーション開発者もレスポンスの任意の例外を変換するために使用する ことができます。

特定の例外が Pyramid ビューコードから上がった場合に常に呼ばれる ビューを登録するためには、レスポンスを生成したいビュー callable を指す ビュー設定の context として例外クラスあるいはその親クラスのうちの 一つを使用してください。

例えば、 helloworld.exceptions という名前のモジュールに次のような 例外クラスがあるとします:

1
2
3
class ValidationFailure(Exception):
    def __init__(self, msg):
        self.msg = msg

どこかにある 他の コードが helloworld.exceptions.ValidationFailure 例外を上げた場合には常に呼ばれるようにビュー callable を設定することができます:

1
2
3
4
5
6
7
8
from pyramid.view import view_config
from helloworld.exceptions import ValidationFailure

@view_config(context=ValidationFailure)
def failed_validation(exc, request):
    response =  Response('Failed validation: %s' % exc.msg)
    response.status_int = 500
    return response

このビュー登録を拾い上げるために scan が実行されたとすると、 このビュー callable はアプリケーションのビューコードによって helloworld.exceptions.ValidationFailure が上げられる場合は常に起動 されることになります。カスタム root ファクトリ、カスタムトラバーサ、 あるいはカスタムビュー、またはルート述語によって上げられた同じ例外も 捕捉されフックされます。

他の通常のビュー述語も例外ビュー登録と組み合わせて使用できます:

1
2
3
4
5
6
7
8
from pyramid.view import view_config
from helloworld.exceptions import ValidationFailure

@view_config(context=ValidationFailure, route_name='home')
def failed_validation(exc, request):
    response =  Response('Failed validation: %s' % exc.msg)
    response.status_int = 500
    return response

上記の例外ビューは route_namehome と指定しています。これは ルート一致が home という名前を持っている時にだけそれが呼ばれること を意味しています。そのため、ある例外に対する例外ビューをシステムの中に 複数持つことが可能です: リクエスト状況のセットがビュー登録と一致する時は 「最も特殊な」ものが呼ばれます。

例外ビュー設定を行う場合、正常に使用できない唯一のビュー述語は name です。例外ビューを検索するために使用される名前は常に空の文字列 です。例外ビューとして登録された名前を持つビューは無視されます。

Note

Exception から継承したコンテキストリソース型に対して登録された 通常の (つまり例外ではない) ビューは、正常に動作します。例外ビュー設定が 処理される場合、 2つの ビューが登録されます。一方は「通常の」ビュー として、他方は「例外」ビューとして。これは、 context として例外を 通常のビューに使用できることを意味します。

例外ビューは任意のビュー登録メカニズムで構成することができます: @view_config デコレータまたは命令的な add_view スタイル。

Note

Pyramid の exception view 処理ロジックは pyramid.tweens.excview_tween_factory() という tween ファクトリ関数 として実装されます。 Pyramid 例外ビューの処理が期待され、 pyramid.tweens 設定で tween ファクトリが指定されている場合、 pyramid.tweens 設定リストに pyramid.tweens.excview_tween_factory() 関数を明示的に追加 しなければなりません。それが存在しなければ、 Pyramid は例外ビューの 処理を行ないません。

HTTP リダイレクトを行うためにビュー callable を使う

pyramid.httpexceptions.HTTPFound クラスを使用して HTTP リダイレクトを発行することができます。このクラスのインスタンスを 例外として上げるか戻り値として返せば、クライアントは “302 Found” レスポンスを受け取るでしょう。

これを行うために、 pyramid.httpexceptions.HTTPFound インスタンス を 返す ことができます。

1
2
3
4
from pyramid.httpexceptions import HTTPFound

def myview(request):
    return HTTPFound(location='http://example.com')

または、それを返す代わりに HTTPFound 例外を上げることができます。

1
2
3
4
from pyramid.httpexceptions import HTTPFound

def myview(request):
    raise HTTPFound(location='http://example.com')

インスタンスが例外として上げられる場合、それはデフォルト exception response ハンドラによって捕捉され、レスポンスへと変換 されます。

ビュー callable の中でフォーム送信を扱う (Unicodeと文字集合の問題)

ほとんどのウェブアプリケーションは、ウェブブラウザおよび様々な他の クライアントからフォーム送信を受け取る必要があります。 Pyramid では、 フォーム送信を扱うロジックは常に view の一部です。 WebOb APIを使用してフォーム送信データを処理する方法の一般的な 概要については、 Request and Response ObjectsWebObドキュメンテーション内の “Query and POST variables”. を見てください。 Pyramid は、リクエストとレスポンスの実装については WebOb に任せています。また、フォーム送信データの取り扱いはリクエスト実装の 特性です。 WebOb のリクエスト API を理解することは、フォーム送信データを 処理する方法を理解するための鍵です。

Pyramid ビュー内でフォーム送信データを処理しようとする場合、 意識する必要のあるいくつかのデフォルトがあります。フォーム送信データに 上位ビットが立った (つまり非 ASCII) 文字が含まれていることは、 非常に一般的です。また、 UTF-8 符号化はウェブ上で文字データに使用される 最も一般的な符号化です。バイト文字列を扱ったり格納したりするよりも Unicode 値の方がはるかに健全なので、 Pyramid はフォーム送信値を 可能なら UTF-8 から Unicode へ暗黙的にデコードするように WebOb リクエスト機能を構成します。ビューコードが request.params, request.GET あるいは request.POST API によってフォームフィールド 値を得る場合、暗黙のデコードが起こります (これらの API に関する詳細に 関しては pyramid.request を参照)

Note

多くの人々が Unicode と UTF-8 の間の違いに混乱を見い出します。 Unicode は、世界の書記体系のうちのほとんどをサポートするテキストを表わす ための規格です。しかし、転送と記録のために Unicode データをバイトへ エンコードするための多くの方法があります。 UTF-8 は Unicode のための 特定の符号化で、 ASCII と後方互換性を持ちます。このため、データの 大部分が ASCII 文字であるような場合に UTF-8 はデータをエンコードする のに非常に便利です。それはウェブ上では大部分正しいです。 UTF-8 は URL のための標準文字符号化でもあります。

例として、次のようなフォームページがブラウザクライアントに表示され、 その action が何らかの Pyramid ビューコードを指していると 仮定しましょう:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
  </head>
  <form method="POST" action="myview">
    <div>
      <input type="text" name="firstname"/>
    </div>
    <div>
      <input type="text" name="lastname"/>
    </div>
    <input type="submit" value="Submit"/>
  </form>
</html>

Pyramid アプリケーション内の myview ビューコードは、 request.params によって返された値が str 型ではなく unicode 型になると想定 しなければなりません 。上記のフォームからフォームポスト を受け取るのに下記のコードは動くでしょう:

1
2
3
def myview(request):
    firstname = request.params['firstname']
    lastname = request.params['lastname']

しかし、次の myview ビューコードは動かないかもしれません。 request.params から取得したデコード済みの (unicode) 値を デコードしようとしているからです:

1
2
3
4
5
def myview(request):
    # the .decode('utf-8') will break below if there are any high-order
    # characters in the firstname or lastname
    firstname = request.params['firstname'].decode('utf-8')
    lastname = request.params['lastname'].decode('utf-8')

暗黙のデコードが確実 (reliably) に動作するため、 Pyramid ビューに ポストするすべてのフォームをレンダリングする際は必ず明示的に charset エンコーディングを UTF-8 と定義するようにします。これは、レスポンスの Content-Type ヘッダの中で ;charset=UTF-8 を指定することによって、 あるいは上記のフォームのようにフォームを含むページの HTML head で charset が UTF-8 であることを示す meta http-equiv タグによって 行うことができます。既知のすべてのブラウザクライアントは、フォームを 送信する際にはそのフォームを含むレスポンスの Content-Type 値によって 推測されたのと同じ文字集合を使ってフォームデータをエンコードすべきで あると仮定するので、これは明示的に行われなければなりません。フォームデータ をエンコードするためにどの charset を使用すべきかをブラウザクライアント に伝える一般的に受け入れられた方法はこれ以外にありません。エンコードを 明示的に指定しなければ、ブラウザクライアントはフォームデータを送信する前に デフォルト文字セットにエンコードすることを選択します。それはサーバーが 期待する UTF-8 ではない可能性があります。非 UTF8 charset でエンコードされた フォームデータを含むリクエストがビューコードによって扱われるなら、いずれ 他の文字集合でエンコードされたフォームデータ内の 8 bit 文字をデコード できずにビュー内で実行されたリクエストコードで (例えば request.params['somename'] がアクセスされた場合に) エラーが発生するでしょう。

レスポンスを生成するために Response クラスを 使用しているか、あるいは render_template_ テンプレート API を使用して いれば、 Content-Type ヘッダーに UTF-8 charset がデフォルトとして 自動的にセットされます。明示的な charset のない Content-Type ヘッダ を返した場合、テキスト型のレスポンスコンテントタイプ (例えば text/htmlapplication/xml など) に対しては、あなたの代わりに リクエスト (訳注: レスポンスの間違い?) がレンダリング時に Content-Type ヘッダー値に ;charset=utf-8 トレーラーを加えます。独自のレスポンス オブジェクトを使用していれば、これを自分自身で確実に行う必要があるでしょう。

Note

request.params, request.GET, request.POST によって 得られるリクエスト params の だけが Pyramid デフォルト設定の もとでユニコードオブジェクトに暗黙にデコードされます。キーは、 依然として(バイト)文字列です。

ビュー callable の引数/呼び出し規約を変更する

通常、ビュー callable は単一の引数 request だけを受け取ると定義されます。 しかし、その代わりにビュー callable はクラス、関数あるいは 2 つ の位置引数 を受け取る何らかの callableとして定義されることも可能です: 1つ目の引数と して context リソース、 2 つ目の引数として request です。

このスタイルで定義されたビュー関数に渡される contextrequest の各引数は、以下のように定義することができます:

context

ツリー traversal あるいは URL dispatch によって見つかった resource オブジェクト。

request

現在の WSGI リクエストを表わす Pyramid リクエストオブジェクト。

次のタイプがこのスタイルのビュー callable として動作します:

  1. 2つの引数 context, request を受け取る関数。例えば:

    1
    2
    3
    4
    from pyramid.response import Response
    
    def view(context, request):
            return Response('OK')
    
  1. context, request を受け取る __init__ メソッドと、 引数を受け取らない __call__ メソッドを持つクラス。例えば:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from pyramid.response import Response
    
    class view(object):
            def __init__(self, context, request):
                    self.context = context
                    self.request = request
    
            def __call__(self):
                    return Response('OK')
    
  1. context,request を受け取る __call__ メソッドを持つ 任意の callable 。例えば:

    1
    2
    3
    4
    5
    6
    from pyramid.response import Response
    
    class View(object):
            def __call__(self, context, request):
                    return Response('OK')
    view = View() # this is the view callable
    

このスタイルの呼び出し規約は、コンテキストオブジェクトがビュー callable のコード自身によって頻繁に使用される traversal に基づく アプリケーションで最も有用です。

どのビュー呼び出し規約が使われていても、ビューコードは常に request.context によってコンテキストにアクセスする必要があります。

設定変数をビューへ渡す

設定 .ini ファイルからビューに変数を渡すことに関する情報は Deployment Settings を参照してください。

Pylons 1.0 スタイルの “コントローラ” ディスパッチ

pyramid_handlers という名のパッケージ (PyPI から利用可能) は Pylons スタイルの「コントローラ」の類似品を提供します。 それは、アプリケーションが URL dispatch を単独で使用する場合に より多くの自動化を提供する特別な種類のビュークラスです。