MongoKit

http://pypi.python.org/pypi/mongokit/0.7.2
mongodbのツールキット。自分でmapper書かなくてよかったのか。
Pylons supportを謳っているのがポイント高い。development.iniとかのiniファイルに接続の設定書けるみたい。
ちょうどこのへんの書き方で自分のだとなんか半端だなーとおもっていたところだったのでありがたい。
さっそく使ってみる。
現時点での最終更新が2011-08-30でversion0.7.2。旬ですね。

PyCon mini JP

ひさびさのこうしん。仕事ともんはんで忙しいんだよ。
PyCon mini JP#pyconjp)ってイベントがあったとですよ。今日。
たまたまお手伝いに参加する機会に恵まれたのでいってきました。
お手伝いっていってもエレベータホールで「こちらでーす」っていうのとエレベータで上がったり下がったりする刺身タンポポ的な任務でしたけれども。
#なめてましたが案外しんどいです

個人的に是非見たいと思っていたのが、

  • Sphinx 1.1 のi18n機能紹介(IanLewisさん)
  • テンプレートエンジンの高速化と失敗談について(桑田誠さん)
  • 最速WSGIサーバー研究会(松原豊さん)

の三つ。Sphinxはエレベータのお守りしててほとんどダメだったけど、桑田さんと松原さんのはなんとか聞けました。松原さんのは絶対見たかったからよかったー。
前に使ったらしきプレゼン資料を見てあったので、なるほどそういう意図なのかーとか、予習ってだいじだよねっていうはなし。うん。
今回使ってたのはこっち。

忘れないうちに今日分かったこと。

  • 文字列処理はperlだよというのは世迷言でなくほんとだった
  • None→何かとかtime→何かまあだいたい文字列とか、”変換する”っつうのは小さいようでもちゃんとコストあんだよ
  • 決まりきった何かを吐くって分かってるとこまで毎回処理させっから遅いんだよ
  • あたしはこういうの開発してるんですよっていうネタがあったほうが絶対よい
  • Tenjinやばい。速い。
  • Pythonでは発表資料の冒頭に「おまえ誰よ?」というページを用意するべき

あれ当たり前なことばっかり書いておる。
なんというか、そんなのわかってますよやだなーハハハとか思うようなことでも、もっと突き詰めて考えたり、ベンチ通すときっちり数字になって出てくる、こんなに違うんだよっていうのを見せてもらったのはとても刺激になりました。
なんとなくわかった気でいただけ、っていうことがとても多かった。
一部だけしか聴けなかったけど、Ianさんのトークはとても魅力的だった。
北神さんの異常なハイテンションの発表も面白かった。Pongのデモやってた。「この設定のコンピュータは最強で~」とか、ボールのY軸常に追尾とかきたないだろそれ。ハードまで触れると、やれることがこう広げられるんだよという例は刺激的だった。
追記:写真とってたんだった。
北神さんのデモ機
NVDAの発表はえらい盛り上がってたみたいだけど聴けなかった。無念。
LTで出てた、画面遷移図を作るライブラリの話が極めて興味深かった。あれどっかに資料ないかなあ。(ついき:あった。これだ。blockdiag それとプレゼン資料もあった。)
カンファレンスとか参加したのも初めてで、初参加がお手伝いって空気感も分からないまま現場にいちゃったわけですが、実際いってみるととても楽しいものでした。

参加してる方に便乗していっしょにたばこ行ったんだけど、その後ご一緒した方が登壇した上、あたし的メインイベントのmopemopeさんだったというのが超びっくりでした。
次回もまた行く。
帰る頃にはヨタヨタするくらい消耗したけど、楽しかった!

しかしなんだ、PylonsとかGenshiとかまったく聞こえてくることすらなかったな。うわん。

wsgi経由だといろいろ勝手が変わる

StackOverFlowになんか書くと、すぐspamくるようになるなー

タイトルで言いたいことはすべていってるんだけど、PylonsのチュートリアルとかだとPasteサーバ?だかで起動とかなってて、あほかそんなんapacheやlighttpdの例出さんでどうするんじゃー現実的じゃないだろー
それともあれか、python触るからには既存環境との折り合いとかそんなんは一回忘れろってことですか(-_-;

PinMarchというblogを発見。

そうそう。うれしい。
というメモ。

logging in pylons

ロギングってのがあたしには極めてややこしい。ハンドラってものをちゃんと理解していないせいだ、とおもう。
なんだよハンドラって。説明聞くと分かった気になるけどイメージはつかめてない。
logging モジュール←ドメインみて「ん?」 東大だって。

log.addHandler( logging.StreamHandler(sys.stdout))

この記述が大事っぽいことは分かった。ログ出るようになったし。
でもこんなん、毎回毎回ハンドラ指定するためにimport logging, sysってやんのー?めんどくさくないー?

追記:
controllers/__init__.py

# -*- coding: utf-8 -*-
import logging, sys
log = logging.getLogger(__name__)
log.addHandler( logging.StreamHandler(sys.stdout))

こうして、
アクションというかコントローラの中で

前略
log.error("aaaaaaa")
後略
[Sun Nov 21 12:05:57 2010] [error] aaaaaaa

でたな。

SQLAlchemyでUNIQUE制約

ship_idとskill_idの組がUniqueであるっつうテーブル制約を加えたい。

table_obj= Table('table_a', metadata,
    Column('id',        Integer, primary_key=True),

    Column('ship_id',   Integer, ForeignKey('ship.id') , unique=True),
    Column('skill_id',  Integer, ForeignKey('skill.id'), unique=True),
    )

こうやりがち。でもこれぶー。ship_idとskill_idにそれぞれUnique制約かかっちゃって、何にも入らないテーブルの一丁上がり。

table_obj= Table('table_a', metadata,
    Column('id',        Integer, primary_key=True),

    Column('ship_id',   Integer, ForeignKey('ship.id')),
    Column('skill_id',  Integer, ForeignKey('skill.id')),
    UniqueConstraint('ship_id', 'skill_id', name='ship_skill')
    )

UniqueConstraintってのがあったよ。これで

CREATE TABLE table_a (
        id INTEGER NOT NULL AUTO_INCREMENT,
        ship_id INTEGER,
        skill_id INTEGER,
        delflg SMALLINT NOT NULL,
        created DATETIME,
        updated DATETIME,
        PRIMARY KEY (id),
        FOREIGN KEY(skill_id) REFERENCES mst_optionskill (id),
        FOREIGN KEY(ship_id) REFERENCES ship (id),
        CONSTRAINT ship_skill UNIQUE (ship_id, skill_id)
)

的なアレになる。よかった。

lazyload & joinedload

#語りかける口調ですがあくまでも自分用のメモです。
へんてこなお任せJoinの仕掛けを、実は帰りがけに見つけておったのですが、なんとかソコまでこぎつけました。
あー定義?だいたい終えたよいちばん大きくて面倒なのは見て見ぬ振りしてるけど。
リレーション?なんか拍子抜けするくらい簡単にできたよ。構造が分かりはじめたらなんのことはないって風だったな。
このあたりは時間とってちゃんとまとめて、あたしみたいなphpを書くのがやっとみたいなパンプキンPGにもSQLAlchemy使える使い始めることくらいはできるようにしてやっからな。
もう$とか->とか書きたくなくなるわ。まあそれはいいや。

タイトルのlazyload と joinedload。説明はよく読まずに使ってみた。Lazyはテキトウなとかそんな意味だったと思うので、適当によろしくやってくれるのであろうと読み取りました心で。joinedloadはジョインしてロードしてくれるんだろうたぶん!!!!

(追記20130301)lazyつうのは遅延評価の事だったのね。必要なときに初めて仕事するよと。

実験に使ったのは、

  • BaseUser
  • NdiUser
  • Server
  • Nation

このよっつ。NDIで使うことを意図しているのでちょっと一般的じゃないですが、UserBasic,UserExtend,Blood,Jenderとかによみかえればいいよ!しるか!
NdiUserってのが、他のテーブルへのキー持ってるの。なんで、NdiUserからjoinしてあれこれ引っ張ってこれるわけだ。
で、session.queryにはそういういろんなオプションの書き方も用意されておるわけだ。
めんどくさい。めんどくさいんだよ……。
で、神パイソニスタさんたちが使う神ORMであらせられるところのSQLAlchemy(以下SA)には、リレーションの設定書いてあるならそれ読んでこっちで適当につないでやるわ、という仕掛けがあるみたいなのね。間違ってたらごめんでも結果はそうだ。

まずはこんな呼び出しをする。

    nu = meta.Session.query(NdiUser).filter_by(id=1).one()
    print nu
    print nu.baseuser
    print nu.server
    print nu.nation

こうすると、nu作るときにSQLクエリ一発、nu.baseuser呼び出す時にもう一発、nu.server呼び出す時にさらに一発投げるのだわ。つどつど、必要なときにSQL投げてんの。なるほどー

で、こんなん。

nu = meta.Session.query(NdiUser).filter_by(id=1).\
    options(lazyload(NdiUser.baseuser)).one()

lazyloadの後ろのカッコの中に、リレーションはってる部品をざらざら並べると、そのようによろしくやってくれるのね。

nu = meta.Session.query(NdiUser).filter_by(id=4).\
    options(lazyload(NdiUser.nation, NdiUser.server, NdiUser.baseuser)).one()

こんなん。lazyloadのとこをjoinedloadにすればまあ結果は同じだけど経緯が違うことがあるみたい。
結果はというと、指定したテーブルに関してはあらかじめクエリ飛ばすわけだから値を持ってる状態になると。
取り出すjoin先のテーブルが分かりきってる場合はそのほうがいいよね。

で、SQL文とかをechoさせながら動作見てたら、
joinedloadはテーブル一個だけつなぐ指定のときはSQL側でもjoinでつなげたクエリ発行してて、
つなぐテーブルが二個以上になるとjoinやめて個別にクエリ投げてるの。
lazyloadは連結したいテーブルの数に関わらず、joinはしないで個別に呼クエリ投げてるの。
なんでーなんでだー
あたしのやろうとしていることのレベル感でいくと、そんなもんはどっちでも結果同じなんだけど、気になるね。
というところまで今日は進んだのでした。
ネック解消したおかげで、ちょっと気分が軽い。

websetup.py

Pylonsで作ったアプリの初期化にはwebsetup.pyをつかう。
コマンドは
paster setup-app development.ini
これね。
websetup.pyのなかみはこんなかんじ

# -*- coding: utf-8 -*-
"""Setup the ndi application"""
import logging

import pylons.test

from sqlalchemy import *
from ndi.config.environment import load_environment
from ndi.model.meta import Session, Base

log = logging.getLogger(__name__)

def setup_app(command, conf, vars):
    """Place any commands to setup ndi here"""
    # Don't reload the app if it was loaded under the testing environment
    if not pylons.test.pylonsapp:
        load_environment(conf.global_conf, conf.local_conf)

    # Create the tables if they don't already exist
    Base.metadata.create_all(bind=Session.bind)

    #あとでimportの後は*にするが定義終わってないのもあるため
    #作成途中なのでいっこずつ付け足しては投入しております
    from ndi.model.member import BaseUser,NdiUser
    from ndi.model.master import Server,Nation,OptionSkill,SeaAreaL,SeaAreaS,Port

    #テーブル作成
    BaseUser.metadata.create_all(bind=Session.bind)
    NdiUser.metadata.create_all(bind=Session.bind)

    Server.metadata.create_all(bind=Session.bind)
    Nation.metadata.create_all(bind=Session.bind)
    OptionSkill.metadata.create_all(bind=Session.bind)
    SeaAreaL.metadata.create_all(bind=Session.bind)
    SeaAreaS.metadata.create_all(bind=Session.bind)
    Port.metadata.create_all(bind=Session.bind)


    from ndi.model import meta

    #マスタ系のデータ入れてくお
    #Server
    try:
        meta.Session.add(Server(id=1,name='notos'   ))
        meta.Session.add(Server(id=2,name='zephyros'))
        meta.Session.add(Server(id=3,name='euros'   ))
        meta.Session.add(Server(id=4,name='boreas'  ))
        meta.Session.commit()
    except Exception,e:
        print 'Abort:Server'
        meta.Session.rollback()

以下略。このあと延々データ投入が続く。
親の仇みたいに定義書きまくってpaster setup-app development.iniすると、画面が滝のようになってきもちいいいいいいいい
あまりに楽しいので、DBのテーブル全部消す→paster setup-app development.ini→気持ちいいいいいい→DBのテー(略
とかやってます。作業すすみません。進めよ。

もういろいろわすれてる

調べなおしだ何もかもー
とはいえ、arisueさんfujishinkoさんperezvonさん_2F_1さんあたり通読で解決するはずだ。

SQLAlchemyの各リレーショナルの書き方テンプレート

autoload sqlalchemy cache

SQLAlchemy + MySQLでUnicodeの問題を解決

[Python][SQLAlchemy] declarativeプラグイン
↑あたしのmodel変な書きかたしてるなと思ったらコレだ。

もーほんとこの神様方には結婚申し込みたい。あたしはネカマですが。