Pyramidのチュートリアルをやってみる③ 〜 wikiアプリケーションの設計(ビューの定義)
Pyramidのチュートリアルをやってみる② 〜 wikiアプリケーションの設計(モデルの定義) - [[ともっくす alloc] init]の続き.
今回はwikiアプリケーションのビューの定義まで.
パッケージの依存関係
setup.py
今回のwikiアプリケーションでは,reStructuredTextマークアップを使えるようにするために,docutilsパッケージが必要となる.
そこで,setup.pyでこの依存関係をsetupメソッド内のrequiresパラメータに割り当てることによってdocutilsパッケージへの依存を追加する.
setup.py内のrequiresを以下のように変更する.
requires = [ 'pyramid', 'SQLAlchemy', 'transaction', 'pyramid_tm', 'pyramid_debugtoolbar', 'zope.sqlalchemy', 'waitress', 'docutils', ]
setup.py developの実行
新たに追加された依存パッケージ(docutils)を登録,取得するために,
$ python setup.py develop
と,実行する.
views.py
views.pyを以下のように変更する.もはや,チュートリアルそのまま.
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), )
まあ,なんとなくわかるかと.
で,各メソッドは以下のような役割を持つ.
- view_wiki()
- wiki自体を表示する
- view_page()
- 個々のページを表示する
- add_page()
- ページの追加を可能にする
- edit_page()
- ページの編集を可能にする
詳しい説明は,ここを読めばわかるでしょう.
> ビューを定義する — The Pyramid Web Application Development Framework v1.4.1 (翻訳)
テンプレート
追加したview_page,add_page,edit_pageビューはtemplateを参照していて,これらのテンプレートはtemplatesディレクトリの中にある.
また,Chameleonテンプレートとして認識されるためには.pt拡張子でなければいけない.
PyramidはChameleonテンプレート以外にも,Makoテンプレートがサポートされている.
使い方等は,他の素晴らしいサイトを参照すべし.
view.pt
view.ptを以下のように変更.
<!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">© Copyright 2008-2011, Agendaless Consulting.</div> </div> </body> </html>
edit.pt
edit.ptを以下のように変更.
<!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">© Copyright 2008-2011, Agendaless Consulting.</div> </div> </body> </html>
ルートを追加
URLからコードへのマッピングをadd_route()メソッドで追加する.
以下のようなルートを追加する
- /
- view_wikiというルート名,つまりview_wikiビューにマッピング.トップページ.
- /{pagename}
- view_pageというルート名,つまりview_pageビューにマッピング.pagenameというタイトルのwikiページ.
- /add_page/{pagename}
- add_pageというルート名,つまりadd_pageビューにマッピング.pagenameというタイトルのwikiページを追加するためのページ.
- /{pagename}/edit_page
- edit_pageというルート名,つまりedit_pageビューにマッピング.pagenameというタイトルのwikiページを編集するためのページ.
__init__.py内のmainメソッドを:
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()
と,変更する.
アプリケーション
起動
ここで一旦アプリケーションを起動してみる.
できません
…なんてことはありません.
はい,起動.
$ pserve development.ini --reload Starting subprocess with file monitor Starting server in PID 7139. serving on http://0.0.0.0:6543
http://localhost:6543にアクセス.
ちゃんと,http://localhost:6543/FrontPageにリダイレクトされて,FrontPageの説明が載ってる.
この「This is the front page」っていうのは,initializedb.pyに記述した
model = Page('FrontPage', 'This is the front page')
の部分が反映されていることになる.
データの登録
次は,データを登録してみようと.
http://localhost:6543/add_page/Pyramidにアクセスすることで,Pyramidというwikiページを追加することができる.
テキストエリアの中に,
Pyramid is a *small*, *fast*, *down-to-earth* **Python web application development framework**. It is developed as part of the PylonsProject. It is licensed under a `BSD-like license <http://repoze.org/license.html>`_.
と記述する.
こんな感じ.
で,saveすると,http://localhost:6543/Pyramidに飛ばされて,こんな感じのページに.
しっかりと,マークアップされている.
PylonsProjectのリンクは,PylonsProjectのwikiページを追加するためのページへのリンクになっている.
(BSD-like licenseのリンクは, BSD-like licenseの外部ページへのリンクで,reStructuredTextによるマークアップ)
views.pyで,
r"\b([A-Z]\w+[A-Z]+\w+)"
という正規表現と,
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)
というcheckメソッドを使っている.
この正規表現にマッチする語(大文字で始まり,途中にも大文字が現れるような文字列)がテキストにある場合,
- テーブルに保存されていれば,そのwikiページへのリンク
- テーブルに保存されていなければ,そのwikiページを追加するページへのリンク
に置き換えられる.
そのため,PylonsProjectという語にリンクが貼られている.
簡単にwikipediaもどきが作れた!
ということで,今回はこんな感じで.
次 > Pyramidのチュートリアルをやってみる④ 〜 wikiアプリケーションの設計(認証の追加) - [[ともっくす alloc] init]
前 > Pyramidのチュートリアルをやってみる② 〜 wikiアプリケーションの設計(モデルの定義) - [[ともっくす alloc] init]