2014年1月28日火曜日

6. Python Pyramid + MySQL ついでに Mako から Jinja2

Djangoじゃないのをやってみようということで、Pyramidをさわってみる。
そのときの記録。
久しぶり。
今回は、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

最初に、pyramid_blogr のソースをそのまま実行してみます。
pyramid_blogr をこつこつとつくっていくのは日を改めて。

  1. virtualenv を作成して、pyramid の環境を作る
    env_pyramid_blogr という名前で環境を作りました。
    $ virtualenv --no-site-packages env_pyramid_blogr

    つくったディレクトリに、pyramid をインストールします。
    $ cd env_pyramid_blogr/
    $ bin/pip install pyramid

  2. ソースのダウンロード
    git で clone します。
    $ git clone https://github.com/Pylons/pyramid_blogr

  3. 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 が表示されます。


  4. 日本語入れるとこける
    タイトルに日本語を入力するとこけます。

    この状態で保存すると「pyramid_mako.MakoRenderingException」と言われます。

    なんだかよくわかりませんが、ここんとこを修正すると直りました。
    models.py の slug() を修正します。「encode('utf-8')」を追加しました。
    -- OLD --
        @property
        def slug(self):
            return urlify(self.title)
    

    -- NEW --
        @property
        def slug(self):
            return urlify(self.title.encode('utf-8'))
    





で、これを MySQL にするには、ここを修正します。
  1. 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

  2. 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'')

  3. 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)

これで動くようになりました。