うーむ

リロードするとすぐpylonsのエラー画面に逝っちゃう。
処理さばききれてないような(-_-;?
こりゃなんだとおもって、しばしの間F5おしっぱ→んでtopを見てみると

top - 21:41:43 up 23 days, 21:36,  6 users,  load average: 75.41, 70.90, 57.37
Tasks: 216 total,   2 running, 214 sleeping,   0 stopped,   0 zombie
Cpu(s):  2.0%us,  2.0%sy,  0.0%ni,  0.0%id, 96.1%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   1008488k total,   995396k used,    13092k free,     1352k buffers
Swap:  3068924k total,   965320k used,  2103604k free,    19380k cached

ろーどあべれーじ70ってアンタ……。
MySQLつなぎに行くとこが重たいとこうなるみたい。DB舐めにいかないページではあんまこういうことがおこらないぽ。
まいったなーDBのコネクション数とかなんか見ないとダメだなー。
まあ見たくってもいま何もできないくらい重い状態が30分くらい続いてるんですが。

自己参照

自己参照のrelation @ sqlalchemy 0.5(sklave)
これか?既に試したきはする。。。
問題は、こーやって参照しに行く先が、あたしの場合は3個もあって、常に3個なわけではないということだなー

けど、愚直に見っけたもんをいちいちやるしかないのだ。あたしは変なトコをすっとばして悩む癖あるからな。
エンジンが書き出してくれてるところを気づかずに勝手に一行消して「うごかねえぇぇ」とか言ってた品。

進捗

一度動いていたはずのアプリを修理・改修しながら再構築するっていうのは、なんかポンコツのレストア作業をやっているような感覚になりますね。
なおってもポンコツになる予感しかしないのだけれど、ホビーだから!ホビー!

キレイにマッピングできなくてもやもやするというのを1週間近く続けております。
パーツの表現で、親子関係になるんだけど自己参照って言うの?部品の材料をぶら下げる的な構造がきれいに決まらない。なんだーなんでだー
図解つきで英文書いてstackoverflowに投稿しよう。
いわゆる親子関係なんだけど、

部品テーブル
-id
-name
-材料1_id
-材料2_id
-材料3_id

この材料1~3_idには同じく部品テーブルがぶら下がる。
んでこれをsqlalchemyにやらせたいわけなんだけど、
「どのテーブルのこといってるかわっかりませーんプップー」
join(outerjoin)構文では値引っ張れるんだけど、なんかDBの構造を引きずってテンプレまでヨタヨタ歩いてくるのがとても醜い。
というのを英文にする。宿題。

いまはこんな書き方。

Mat1 = aliased(Part)
Mat2 = aliased(Part)
Mat3 = aliased(Part)

Session.query(Part,Mat1,Mat2,Mat3).filter(and_(ShipPart.genre_id==2)).\
                       outerjoin( (Mat1, ShipPart.mat1id==Mat1.id)....

用は満たしてるんだけども、それぞれタプルに分かれてくるし、
Part.Mat1.idとか
Part.Mat1.nameとか、わかるかな!そういう引っ張りかたしたいわけ!

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はしないで個別に呼クエリ投げてるの。
なんでーなんでだー
あたしのやろうとしていることのレベル感でいくと、そんなもんはどっちでも結果同じなんだけど、気になるね。
というところまで今日は進んだのでした。
ネック解消したおかげで、ちょっと気分が軽い。