SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.
SlideShare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.
Successfully reported this slideshow.
Activate your 14 day free trial to unlock unlimited reading.
2.
お前誰よ
I aodag
I Atsushi ODAGiri
I 所属
I ビープラウド
I Pylonsproject.jp
3.
Pyramid
I 特徴
I Web アプリケーションフレームワーク
I ドキュメント、テストがしっかりしてるコミュニティ
I 長所
I 押しつけがない
I フレームワーク自体が拡張可能
I コンポーネントで整理された実装とAPI
I 短所
I 押し付けがない
I フルスタックでないので各種ライブラリの知識が必要
I 柔軟性の高さは諸刃の剣でもある
4.
使う理由
I SQLAlchemy と一緒に
I 認証方法や権限設定などがアプリケーションに絡んで複雑
I 保存先がDB でない場合などフルスタックがいらない
I アレがきらいだから
5.
pyramid の歴史
I repoze.bfg 0.1 2008-07-08
I repoze.bfg 1.0 2009-07-05
I repoze.bfg 1.3b1 2010-10-25
I pyramid 1.0a1 2010-11-05
I pyramid 1.0 2011-01-30
I pyramid 1.1 2011-07-22
I pyramid 1.2 2011-09-12
I pyramid 1.3 2012-03-21
I pyramid 1.4 2012-12-18
I pyramid 1.5 2014-05-31
6.
インストール
$ pyvenv.py .venv
$ . .venv/bin/activate
(.venv)$ pip install pyramid
I pyvenv
I pip
7.
Hello Pyramid
from pyramid.config import Configurator
from pyramid_view import view_config
@view_config(route_name="hello")
def hello(request):
name = request.matchdict["name"]
body = "Hello {name}".format(name=name)
request.response.text = body
return request.response
def main(global_conf, **settings):
config = Configurator(settings=settings)
config.add_route("hello", "/hello/{name}")
config.scan(".")
return config.make_wsgi_app()
8.
Hello Pyramid
I config.add_route
I Web アプリケーションで扱うURL パターンを登録する
I config.scan
I view_config などのvenusian デコレータのコールバックを実
行する
I view_config
I scan のタイミングでview を登録する
I request_method やroute_name などの条件を指定
9.
TODOLIST アプリケーションその1
I モデル
I Task
I name
I 機能
I タスク一覧
I Task をすべて表示する
I タスク完了のボタンを表示する
I タスク追加のフォームを表示する
I タスク追加
I Task を作成して、タスク一覧に戻る
I タスク終了(削除)
I Task を削除して、タスク一覧に戻る
10.
SQLAlchemy を使う
pip install pyramid_tm pyramid_sqlalchemy
config.include("pyramid_tm")
config.include("pyramid_sqlalchemy")
I pyramid_tm
I transaction を利用した包括的なトランザクション管理
I エラー発生時はロールバック
I pyramid_sqlalchemy
I zope.sqlalchemy
I sqlalchemy.url
12.
ビュー:タスク一覧
@view_config(route_name="top",
request_method="GET",
renderer="templates/index.mako")
def index(request):
tasks = Task.query.all()
return dict(tasks=tasks)
I route_name
I request_method
I renderer
13.
ビュー:タスク作成
@view_config(route_name="top",
request_method="POST")
def create_task(request):
name = request.params["name"]
task = Task(name=name)
DBSession.add(task)
location = request.route_url("top")
return HTTPFound(location)
I request.params
I request.route_url
I HTTPFound
14.
ビュー:タスク削除
@view_config(route_name="task_finish",
request_method="POST",
renderer="templates/index.mako")
def delete_task(request):
task_id = request.matchdict["task_id"]
task = Task.query.filter(Task.id == task_id).first()
if task is None:
raise HTTPNotFound
location = request.route_url("top")
return HTTPFound(location)
I request.matchdict
15.
Pyramid で使えるテンプレート
I Pyramid1.0 から1.4 までmako, chameleon サポートが
Pyramid 自体に含まれていた
I Pyramid1.5 以降で標準サポートはstring, json のみ
I 標準サポート
I json
I string
I ライブラリでサポート
I pyramid_mako
I pyramid_chameleon
I pyramid_jinja2
I など
16.
pyramid_mako
pip install pyramid_mako
config.include("pyramid_mako")
I pyramid_mako
I mako テンプレートを使ったrenderer
I include すると“.mako” 拡張子で指定したレンダラーでmako
テンプレートを利用できる
20.
TODOLIST アプリケーションその2
I Route とTraversal とView を活用する
I アプリケーションのロジックはリソースで行うようにする
I CSS などを適用
I deform でフォームを作る
I Task をまとめるTodoList モデル
I ビューであれこれやらないようにする
21.
Pyramid のView が呼ばれるまで
I パターンマッチによりroute を決定
I route に設定されたfactory でresource を作成
I matchdict にtraverse がある場合はresource をトラバース
I 残りのURL を消費しきる
I リソースが__getitem__を持っていない
I 残りのURL が@@ で始まる(ビュー名)
I トラバース結果がcontext となる
I route, context, request method などの条件からview を決定
I view を呼び出す
22.
route とresource factory
config.add_route(
"task",
"/todolists/{todolist_id}/tasks/{task_id}/*traverse",
factory=".resources.task_factory")
I factory
26.
ビューが呼び出されるまで
I URL: /todolist/1/tasks/2/@@finish
I Route: tasks にマッチ
I route_name: tasks
I todolist_id: 1
I task_id: 2
I travarse: @@finish
I tasks route のfactory であるtask_factory が呼び出される
I TaskResource インスタンスがリソースとして作成される
I URL の残りが@@finish となりトラバーサル終了
I ビュー名finish
I task_finish が呼び出される
27.
Deform/Colander でフォーム作成
I Colander
I スキーマ、バリデーションライブラリ
I Deform
I フォームライブラリ
I Peppercorn
I HTML フォームで構造化したデータを扱うためのパーサー
28.
Deform/Colander/peppercorn の動作
I appstruct, pstruct, cstruct
I アプリケーションモデルなどをappstruct にして渡す
I deform がappstruct をフォームウィジェットとともにHTML
にする
I ブラウザからsubmit されるとパラメータはpstruct で渡され
てくる
I peppercoron でpstruct をcstruct に変換
I colander でcstruct をappstruct に変換
29.
Colander スキーマ
import colander as c
import deform.widget as w
class TodolistSchema(c.Schema):
name = c.SchemaNode(c.String())
description = c.SchemaNode(c.String(),
widget=w.RichTextWidget())
I Schema クラス
I SchemaNode
I widget
I deform へのヒントとしてウィジェットを設定する
I 抽象的なスキーマ情報にこういう詳細が入るのはちょっとや
だ(´・ω・`)
30.
pyramid_deform
@view_config(....)
class TodolistForm(FormView):
schema = TodolistSchema()
buttons = ('save',)
@property
def context(self):
return self.request.context
def save_success(self, values):
todolist = self.context.add_todolist(**values)
return HTTPFound(todolist.url)
I FormView を継承してビューを実装する
I schema でcolander スキーマを指定
I buttons でボタンの名前(‘save’) を設定しておくと、対応する
メソッド(save_success) がバリデーション後に呼び出される
32.
appstruct
class TodolistResource(object):
...
def appstruct(self):
return dict(name=self.todolist.name,
description=self.todolist.description)
I ビューのメソッドで詳細に実装したくない
I context に委譲
I FormView はなぜかcontext を持ってないのでrequest 経由で
取得
I appstruct
I deform はフォームの値をdict(appstruct) で受け取る
I appstruct はdeform によってpeppercorn が解釈可能なパラ
メータ(pstruct) をsubmit するフォームとなるようにレンダ
リングされる
33.
pyramid_deform のAPI はあまりきれいじゃない
I 継承ベース
I あまり大きく動作を変えられない
I メソッドオーバーライドによる穴埋め
I フォームバリデーション以外のデータを扱えない
I たとえばDB アクセスして重複チェックなどした場合のエ
ラーとかきれいに表示できない
I あまり多くを望まないように
I 単純なマスタデータ入力以上はできないと思ったほうがよい
34.
deform の扱い
form = deform.Form(TodolistSchema(), buttons=('save',))
controls = request.params.items()
try:
params = form.deserialize(controls)
except ValidationFailure as e:
return dict(form=e)
I request.params.items()
I peppercorn はパラメータの順番が重要
I ValidationFailure
I 入力チェックの例外オブジェクト
I エラー情報を含んだフォームをレンダリングする
35.
static_view
I CSS, JS などを取り扱うにはstatic_view を使う
add_static_view("static", "my.todolist:static")
I “static” はURL で使う名前
I “my.todolist:static” はファイルパスここではasset
specification 記法を使っている
I add_static_view で登録したasset はテンプレートなどで
static_url でURL を利用する
I static_url の例
<link rel="stylesheet"
href="${request.static_url(
'deform:static/css/bootstramp.min.css')}">
<script
src="${request.static_url(
'my.todolist:static/js/app.js')}"></script>
36.
Asset Specification
I “{package}:{directory}” のような文字列でパッケージ以下
のディレクトリを表す
I my.todolist:static は
os.path.join(os.path.dirname(my.todolist.__file__), “static”)
で取得できるディレクトリ
39.
Mako テンプレート
I block タグ
I あとから継承先のテンプレートで埋める場所
I next.body()
I 直接継承しているテンプレートの内容をレンダリングする
I レイアウトなど多段に継承するときに必要
I inherit タグ
I 継承テンプレートを指定
I %for, %if, %while など
I Python の各種制御構文と同じ
I インデントブロックじゃないので、%endfor などが必要
42.
pyramid のセキュリティ機構
I authentication_policy
I アクセスしているユーザーが誰なのか? を判定する方法
I authorization_policy
I アクセスするユーザーは何ができるのか? を判定する方法
43.
permission
@view_config(route_name="top",
permission="todolist.view",
renderer="templates/index.mako")
def index(context, request):
return dict(todolists=context)
I view ごとにpermission を決める
I authorization policy で与えられたpermission がview の
permission を含んでいれば、そのview を利用可能
I 適切なpermission を得られなかった場合はforbidden_view が
呼び出される
44.
ACLAuthorizationPolicy
class TodoListResource(object):
...
def __acl__(self):
return [(Allow, self.todolist.user.username,
'todolist.view'),
(Allow, self.todolist.user.username,
'todolist.edit'),
(Allow, self.todolist.user.username,
'task.create'),
]
I context の__acl__ プロパティでpermission を決定する
I __acl__は、pyramid1.5 以降はメソッドでもよい
I この場合はtodolist の持ち主ならtodolist.view などの
permission を与えられる
45.
ログインビュー
@view_config(route_name="login",
renderer="templates/login.mako")
class LoginView(FormView):
schema = LoginSchema()
buttons = ('login',)
def login_success(self, values):
user = authenticate(self.request,
values["username"],
values["password"])
if not user:
return
headers = security.remember(
self.request, user.username)
res = HTTPFound(self.request.route_url("top"),
headers=headers)
return res
46.
pyramid.security API
I security.remember
I authentication_policy に対して、identity(ログインユーザーな
ど) を記録する(ログイン)
I security.forget
I authentication_policy に対して、identity を消去する(ログア
ウト)
47.
User の判定
def authenticate(request, username, password):
user = User.query.filter(
User.username == username).first()
if not user:
return
if not user.validate_password(password):
return
return user
48.
TODOLIST アプリケーションその4
I シングルページアプリケーションにする
I リクエスト、レスポンスでJSON を取り扱う
49.
pyramid のjson 対応
I request.json_body
I リクエストから直接json パースしたオブジェクトを受け取
れる
I json レンダラー
I ビューが返すdict をjson にダンプしてくれる
I オブジェクトが__json__ メソッドを持っているとダンプ中
に呼び出される
I xhr プリディケーション
I view_config でxhr=True としておくと、jquery などのajax リ
クエストはそちらのビューが優先して呼び出される
52.
結局リソースとは
I ビューとモデルの緩衝材
I アプリケーションモデル
I appstruct, __json__, __acl__ などフレームワークへのイン
ターフェイスを提供する
I アダプターパターン
I すべてをリソースでやろうとしないように
I なんでもありになりがち
I コンストラクタで受け取った以上のオブジェクトを扱わない
こと
53.
まとめ
I Pyramid はとても簡単
I 強力なライブラリを活用できる
I JSON アプリケーションのバックエンドとしても優秀
I SQLAlchemy は、がんばって勉強してください
54.
参考文献
I Defending Pyramid’s Design
I http://docs.pylonsproject.org/projects/pyra-mid/
en/1.5-branch/designdefense.html
I Pyramid Documentation
I http://docs.pylonsproject.org/en/latest/docs/pyramid.html
I Deform
I http://deform.readthedocs.org/en/latest/
I Colander
I http://colander.readthedocs.org/en/latest
I pyramid_sqlalchemy
I http://pyramid-sqlalchemy.readthedocs.org/en/latest/
I pyramid_tm
I http://pyramid-tm.readthedocs.org/en/latest/