14: JSONレンダラーを使ったAJAX開発(14: AJAX Development With JSON Renderers)¶
モダンWebアプリケーションはレンダリングされたHTMLより多くの機能があります。動的なページではJSONを用いてサーバーデータのリクエストを行い、JavaScriptを使用してブラウザのUIを更新します。Pyramidはこれを「JSONレンダラー」でサポートしています。
背景(Background)¶
08:テンプレートを使ったHTML生成(08: HTML Generation With Templating) で見たように、ビューの宣言はレンダラを指定できます。ビューからの出力はレンダラーを介して実行され、レンダラーがレスポンスを生成して返します。最初はChameleonレンダラーを使用してから、Jinja2レンダラーを使用しました。
ただしレンダラーはHTMLを生成するテンプレートだけに制限されません。PyramidはPythonデータを受け取り、それをJSONにシリアル化してコンテンツタイプの設定などの他の機能を実行するJSONレンダラーを提供します。実際には独自のアプリケーションのカスタムロジックを含む独自のレンダラーを作成します(または組み込みレンダラーを拡張する)。
手順(Steps)¶
最初に、
view_classes
での結果をコピーします:$ cd ..; cp -r view_classes json; cd json $ $VENV/bin/pip install -e .
We add a new route for
hello_json
injson/tutorial/__init__.py
:1 2 3 4 5 6 7 8 9 10 11
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.add_route('hello_json', 'howdy.json') config.scan('.views') return config.make_wsgi_app()
新しいビューを実装するのではなく、別のデコレータを
views.py
のビューhello
に「スタック」します:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
from pyramid.view import ( view_config, view_defaults ) @view_defaults(renderer='home.pt') class TutorialViews: def __init__(self, request): self.request = request @view_config(route_name='home') def home(self): return {'name': 'Home View'} @view_config(route_name='hello') @view_config(route_name='hello_json', renderer='json') def hello(self): return {'name': 'Hello View'}
最後に新しい機能テストが
json/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 45 46 47 48 49 50
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 TutorialViews request = testing.DummyRequest() inst = TutorialViews(request) response = inst.home() self.assertEqual('Home View', response['name']) def test_hello(self): from .views import TutorialViews request = testing.DummyRequest() inst = TutorialViews(request) response = inst.hello() 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) def test_hello_json(self): res = self.testapp.get('/howdy.json', status=200) self.assertIn(b'{"name": "Hello View"}', res.body) self.assertEqual(res.content_type, 'application/json')
テストを実行します:
$ $VENV/bin/py.test tutorial/tests.py -q ..... 5 passed in 0.47 seconds
Pyramidアプリケーションを以下のように実行します:
$ $VENV/bin/pserve development.ini --reload
Open http://localhost:6543/howdy.json in your browser and you will see the resulting JSON response.
分析(Analysis)¶
以前からビュー関数とメソッドをPythonデータを返すように変更しました。このようなデータ指向のビューレイヤーの変更によってテストロジックの作成が容易になり、テンプレートをビューロジックから切り離せました。
PyramidにはJSONレンダラーとテンプレートレンダラーがあるので、JSONを返すようにする手順は簡単です。JSONを返すようにする場合は同じビューを保持してビューデータのJSONエンコーディングを返却するように設定しました。以下をを行いました:
/howdy.json
をルート名にマップするルートを追加します。- ルート名を既存のビューに関連付ける
@view_config
を提供します。 - ビューの設定を「無効」にすると
hello_json
ルートが表示されて、ルートが一致すると使用されないhome.pt
テンプレートレンダラーではなくJSONレンダラーが使用されます。
事実、純粋なAJAXスタイルのWebアプリケーションでは、Pyramidのビュー述語を使用して、モダンなAJAX実装によって送信された Accepts:
ヘッダーを照合することで既存のルートを再利用できます
PyramidのJSONレンダラは、基本的なPythonのJSONエンコーダを使用しているので長所と短所を受け継いでいます。 たとえばPythonはネイティブJSONのDateTimeオブジェクトをエンコードできません。 PyramidにはJSONレンダラーをカスタムレンダラーで拡張するなどさまざまなソリューションがあります。