そのときの記録。
久しぶり。
今回は、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 件のコメント:
コメントを投稿