そのときの記録。
久しぶり。
今回は、Pyramid Tutorial を MySQL 化してみます。
Pyramid Tutorial の中の pyramid_blogr Tutorial をやってみます。このチュートリアルはテーブルをひとつではなく、複数使うのでこれを選びました。複数といってもふたつですが。
- 環境
MacOS 10.9.1
Python 2.7.6 (MacPortsでインストールしたものを使用する)
MySQL 5.5.33 (MacPortsでインストールしたものを使用する)
Apache 2.2.24 (標準でインストールされているもの)
(mod_wsgi 3.4 はソースを落としてきてインストール)
Eclipse 4.3.1
Pydev 3.2.0
Python 2.7.6 (MacPortsでインストールしたものを使用する)
MySQL 5.5.33 (MacPortsでインストールしたものを使用する)
Apache 2.2.24 (標準でインストールされているもの)
(mod_wsgi 3.4 はソースを落としてきてインストール)
Eclipse 4.3.1
Pydev 3.2.0
pyramid_blogr をこつこつとつくっていくのは日を改めて。
- virtualenv を作成して、pyramid の環境を作る
env_pyramid_blogr という名前で環境を作りました。
$ virtualenv --no-site-packages env_pyramid_blogr
つくったディレクトリに、pyramid をインストールします。
$ cd env_pyramid_blogr/ $ bin/pip install pyramid
- ソースのダウンロード
git で clone します。
$ git clone https://github.com/Pylons/pyramid_blogr
- sqlite で、まず実行
$ cd pyramid_blogr/ $ ../bin/python setup.py develop $ ../bin/pip install -e . $ ../bin/initialize_pyramid_blogr_db development.ini $ ../bin/pserve --reload development.ini
localhost:6543 を見に行くと pyramid_blogr が動作しています。
Users を admin、Password も admin で、Sign in できます。
最初は空っぽなので、entry をつくってみます。
Create a new blog entry をクリックすると、入力できるようになります。
最初の画面に、entry title が表示されます。
- 日本語入れるとこける
で、これを MySQL にするには、ここを修正します。
- development.ini と production.ini のデータベースの接続設定を修正
sqlite を mysql にする。
-- OLD --
sqlalchemy.url = sqlite:///%(here)s/pyramid_blogr.sqlite
-- NEW --
sqlalchemy.url = mysql://pyramid_user:password@localhost:3306/pyramid_blogr?charset=utf8&use_unicode=1 sqlalchemy.pool_recycle = 3600
- pyramid_blogr/models.py にある型の import をしているところを修正
Text, Unicode, UnicodeText をやめて、String にする。
-- OLD --
from sqlalchemy import ( Column, Integer, Text, Unicode, #<- will provide unicode field, UnicodeText, #<- will provide unicode text field, DateTime #<- time abstraction field, )
-- NEW --
from sqlalchemy import ( Column, Integer, String, DateTime #<- time abstraction field, )
そして、class User と class Entry にある項目の「Unicode(255)」や「UnicodeText」を「String(255)」に変更する。unique も取り除く。
例えば、こう。
-- OLD --
title = Column(Unicode(255), unique=True, nullable=False) body = Column(UnicodeText, default=u'')
-- NEW --
title = Column(String(255), nullable=False) body = Column(String(255), default=u'')
- setup.py にある requires = [ に mysql-python を追加
requires = [ 'pyramid', 'pyramid_chameleon', 'pyramid_debugtoolbar', 'pyramid_tm', 'SQLAlchemy', 'transaction', 'zope.sqlalchemy', 'waitress', 'wtforms', 'webhelpers', 'mysql-python', ]
動かしてみる前に、MySQL にデータベース「pyramid_blogr」を作成し、そのデータベースのためのユーザーを追加します。
MySQLに入る。
$ mysql -u root -p mysql
データベースの作成。
mysql> CREATE DATABASE pyramid_blogr CHARACTER SET utf8;
そのデータベースのユーザーの作成。
mysql> GRANT ALL ON pyramid_blogr.* TO pyramid_user@localhost IDENTIFIED by "password";
念のために、sqliete のデータファイル「pyramid_blogr.sqlite」を削除しておきます。
MySQL を使っていると言いつつも、このファイルができているときは sqlite をまだ使っているかも。
「development.ini」のあるディレクトリに「pyramid_blogr.sqlite」があります。
これからの作業をするために、そのディレクトリに移っておきます。
setup.py からもう一度。
$ ../bin/python setup.py develop $ ../bin/pip install -e . $ ../bin/initialize_pyramid_blogr_db development.ini $ ../bin/pserve --reload development.ini
localhost:6543 を表示させると、sqlite の時と同じ Pyramid の画面が表示されます。
最後に、wsgi で動かせるようにします。localhost:6543 ではなく localhost/blogr で表示できます。
プロジェクト pyramid_blogr が置かれているディレクトリ、env_pyramid_blogr/ に pyramid.wsgi をつくります。
その内容はこう。このなかにある /Users/foo/env_pyramid_blogr の foo はあなたの名前(?)にしてください。
from pyramid.paster import get_app, setup_logging ini_path = '/Users/foo/env_pyramid_blogr/pyramid_blogr/production.ini' setup_logging(ini_path) application = get_app(ini_path, 'main')
そして、mac os x 10.9 なら /etc/apache2/other/ にあるmodwsgi.conf を修正します。
env_first_app は、すでに動いているウェブアプリです。そんなものが無い人は、ここのところをばっさり切り取ってください。最初の「WSGIApplicationGroup %{GLOBAL}」の2行はそのままです。
それに、env_pyramid_blogr を追加します。
WSGIApplicationGroup %{GLOBAL} WSGIPassAuthorization On # env_first_app WSGIDaemonProcess pyramid_env_app user=foo group=staff threads=4 \ python-path=/Users/foo/env_app/lib/python2.7/site-packages WSGIScriptAlias /app /Users/foo/env_app/pyramid.wsgi <Directory /Users/foo/env_app> WSGIProcessGroup pyramid_env_app Order allow,deny Allow from all </Directory> # env_blogr WSGIDaemonProcess pyramid_env_blogr user=foo group=staff threads=4 \ python-path=/Users/foo/env_pyramid_blogr/lib/python2.7/site-packages WSGIScriptAlias /blogr /Users/foo/env_pyramid_blogr/pyramid.wsgi <Directory /Users/foo/env_pyramid_blogr > WSGIProcessGroup pyramid_env_blogr Order allow,deny Allow from all </Directory>
これで、localhost/blogr を見に行くと・・・
こけます。
mako の rendering エラーです。
What's New In Pyramid 1.5 をみると、mako の扱いが変わってしまったようです。
なぜターミナルからなら動くのか不明ですが・・・。パスが通っているからか?
修正します。
setup.py はこう。「'pyramid_mako',」を requires に追加します。「pyramid_chameleon」はあるので、これを使え、ということか。
requires = [ 'pyramid', 'pyramid_mako', # <--- !!! 'pyramid_chameleon',
pyramid_blogr/__init__.py の main() に「config.include('pyramid_mako')」を追加します。
config = Configurator(settings=settings, authentication_policy=authentication_policy, authorization_policy=authorization_policy ) config.include('pyramid_mako') # <--- !!! config.add_static_view('static', 'static', cache_max_age=3600)
これで動くようになりました。
おまけ。
development.ini と production.ini にこれを追加すると
mako.directories = pyramid_blogr:templates
views.py やテンプレートで、こうだったのが、
renderer='pyramid_blogr:templates/index.mako'こう書けるようになります。
renderer='index.mako'
テンプレートではこう。
<%inherit file="pyramid_blogr:templates/layout.mako"/>が、
<%inherit file="layout.mako"/>となります。
ついでに、Jinja2 を使う場合の修正について。
Mako は Python 風でいいかんじなんだけれど、やっぱり Jinja2 だ、という場合はこうします。Django ぽいですからね。
☆ development.ini
pyramid.includes = に「pyramid_jinja2」を追加します。
「mako.directories = pyramid_blogr:templates」を使っている場合は、その代わりに「jinja2.directories = pyramid_blogr:templates」とします。
☆ pyramid_blogr/__init__.py
config = のところに「config.include('pyramid_jinja2')」を追加します。
ついでに「config.add_renderer(".html", "pyramid_jinja2.renderer_factory")」をしておくと、テンプレートの拡張子を .html にすることができます。
テンプレートの修正です。テンプレートの拡張子は、.mako から .html にしてあります。
Mako から Jinja2 にするので修正が必要です。
「<% ... %>」は「{% ... %}」になります。そのほか、いろいろ。
☆ pyramid_blogr/templates/edit_blog.html
inherit は extends になります。
--- OLD
<%inherit file="layout.mako"/>
--- NEW
{% extends "layout.html" %} {% block content_body %}
って、いちいちやろうかと思いましたが、たくさんあるので、全部載せます。
extends と block content_body は layout.html の修正にも関係します。
{% extends "layout.html" %} {% block content_body %} <form action="{{ request.route_url('blog_action',action=action) }}" method="post"> {% if action == 'edit' %} {{ form.id() }} {% endif %} {% for error in form.title.errors %} <div class="error">{{ error }}</div> {% endfor %} <div><label>{{ form.title.label }}</label>{{ form.title() }}</div> {% for error in form.body.errors %} <div class="error">{{ error }}</div> {% endfor %} <div><label>{{ form.body.label }}</label>{{ form.body() }}</div> <div><input type="submit" value="Submit"></div> </form> <p><a href="{{ request.route_url('home') }}">Go Back</a></p> <style type="text/css"> form{ text-align: right; } label{ min-width: 150px; vertical-align: top; text-align: right; display: inline-block; } input[type=text]{ min-width: 505px; } textarea{ color: #222; border: 1px solid #CCC; font-family: sans-serif; font-size: 12px; line-height: 16px; min-width: 505px; min-height: 100px; } .error{ font-weight: bold; color: red; } </style> {% endblock content_body %}
☆ index.html
{% extends "layout.html" %} {% block content_body %} {% if user_id %} Welcome <strong>{{ user_id }}</strong> :: <a href="{{ request.route_url('auth', action='out') }}">Sign Out</a> {% else %} <form action="{{ request.route_url('auth', action='in') }}" method="post"> <label>User</label><input type="text" name="username"> <label>Password</label><input type="password" name="password"> <input type="submit" value="Sign in"> </form> {% endif %} {% if paginator.items %} {{ paginator.pager() }} <h2>Blog entries</h2> <ul> {% for entry in paginator.items %} <li> <a href="{{ request.route_url('blog', id=entry.id, slug=entry.slug) }}"> {{ entry.title }}</a> </li> {% endfor %} </ul> {{ paginator.pager() }} {% else %} <p>No blog entries found.</p> {% endif %} <p><a href="{{ request.route_url('blog_action',action='create') }}"> Create a new blog entry</a></p> {% endblock content_body %}
☆ layout.html
「${ ... }」を「{{ ... }}」にします。これは何カ所かあります。
--- OLD
${request.static_url('pyramid_blogr:static/pylons.css')}--- NEW
{{ request.static_url('pyramid_blogr:static/pylons.css') }}
ここは重要!!
「{% extends "layout.html" %} {% block content_body %}」に対応するところです。
--- OLD
${next.body()}--- NEW
{% block content_body %}Content Body{% end block content_body %}
☆ view_blog.html
{% extends "layout.html" %} {% block content_body %} <h1>{{ entry.title }}</h1> <hr/> <p>{{ entry.body }}</p> <hr/> <p>Created <strong title="{{ entry.created }}"> {{ entry.created_in_words }}</strong> ago</p> <p><a href="{{ request.route_url('home') }}">Go Back</a> :: <a href="{{ request.route_url('blog_action', action='edit', _query=(('id',entry.id),)) }}">Edit Entry</a> </p> {% endblock content_body %}
index.mako にある、これなんですが・・・
<% from pyramid.security import authenticated_userid user_id = authenticated_userid(request) %>Mako にはできるんですが、Jinja2 には無いみたいなので、views.py をいじります。
☆ views.py
「from pyramid.security import authenticated_userid」を追加。
from pyramid.security import remember, forget, authenticated_userid
「@view_config(route_name='home', renderer='index.mako')」のように、テンプレートファイル名の拡張子を .mako から .html に変更。
「@view_config(route_name='home', renderer='index.html')」となります。
def index_page(request): で「user_id = authenticated_userid(request)」の行を追加して、return で返します。「return {'paginator':paginator, 'user_id':user_id}」
@view_config(route_name='home', renderer='index.html') def index_page(request): user_id = authenticated_userid(request) page = int(request.params.get('page', 1)) paginator = Entry.get_paginator(request, page) return {'paginator':paginator, 'user_id':user_id}
これで、Jinja2 化できたはず。
0 件のコメント:
コメントを投稿