PyCon JP 2012 始まるよー

PyCon JP 2012 開催します!
以前「何故PyConJPの運営に関わっているのか」で書いたように、今年はスタッフとしてがっつり関わってました。

プログラム選んでタイムテーブルを決めたり

講師の方にハンズオンをお願いしたり

Partyの手配をしたり

開催前レポート書いたり

PyCon JP 2012 開催前レポート 第2回 主要セッションの見どころ紹介

PyCon JP 2012 開催前レポート 第3回 ハンズオン・パネルディスカッション紹介

ちょっと責任範囲多過ぎだろって思いつつ頑張ってましたが、それもこれもようやく報われるかと思うと胸アツです。

当日は会場の受付やPartyの受付をしていると思うので、見かけたら声をかけてくれると泣いて喜びます。


残念ながらチケットは既に完売しているのですが、YoutubeのPyConJPチャンネルでライブ配信されるので、チケットが買えなかった方は是非見てください。

日本における年に一度のPythonの祭典を、明日からの3日間思う存分楽しみましょう!

DjangoのGenericForeignKeyとdumpdata

GenericForeignKeyって使いにくい
DjangoのGenericForeignKeyってdumpdata→loaddataするとデータがズレるし使えないよねーって思ってた時期が僕にもありました。
なんでかって言うと、contenttypesの順番がsyncdbする度に変わるから、dumpdataした環境とloaddataした環境でcontenttypesが変わっていて別のモデルに紐付けられちゃうんですね。
前職ではそれを回避するために、対象のモデル群を固定で持ってるGenericForeignKeyっぽいモデルを自前で作ったりもしてました。


でも、そんなことなかった
Django1.2からdumpdataがGenericForeignKeyに対応していたらしく --natural オプションを付ければ問題なくloaddata出来るようになってました。
dumpdataしたjsonを見ればわかるのですが、オプションなしだとcontenttypesのidが入っている箇所がモデル名になっています。
これで気兼ねなくGenericForeignKeyを使えますね!

何故PyConJPの運営に関わっているのか

はじめに
去年もスタッフをやっていたPyConJP2012に今年も関わっています。
去年は途中から参加したのもあってあまり何もしていなかったのですが、今年は何の因果か色々と働いています。
Call for Proposal出してよー」
とか
スポンサー募集中だよー」
とか言ってると
「スタッフやるなんて凄いねー」
みたいな話をされることがあります。
しかもそれが僕なんかより全然凄い人達だったりするので、
(自分も他人も)勘違いしないように全然大したことなんかじゃないってのを記しとくのも良いかなーって思って筆を取ってます。
というか「Pinaxでサイト作るのとか面倒なんじゃよ」って言うただの逃避です…


スタッフやるのってどんな人だと思いますか?
普通イベントのスタッフやる人って

  • 意識が高い
  • 言語が大好き
  • コミュニティ大好き
  • お祭り大好き
  • お世話になってるものに貢献したい

こんな人じゃないかと思うのですが、僕はそういうの全くないのです。
そもそも去年のPyConJPもスタッフじゃなかったら、チケット買って朝起きるのが面倒で行ってなかったんじゃないかってくらい。
死んだ方が良いくらいダメ人間ですね><


じゃ何故去年はスタッフをやったの?
ふと「Python長く使ってる割に仕事で関わる以外の知り合い少ないなー」って思った時に、たまたまスタッフの募集をしていたので、何の気なしに応募してみただけです。
とは言え参加してみたら、スタッフは僕が唯一定期的に顔を出す勉強会の人や同僚が半数以上を締めていて、知り合いはあまり増えなかったんですけどね><
ただその分普通にとけ込めたというか、そもそもMTGを社内でやっていたって地の利もあって何となく続けていた感じです。
去年はParty用の店探したり、当日死にそうな顔で道案内をしていたくらいしかしてなかったし。


何故今年は色々やってるの?
なんででしょう?僕が知りたいです。
強いて言えば、なりゆきですかね。
去年スタッフをやられた方が今年は忙しい人多かったりで少なかったってのが大きいと思います。
「社内でMTGやるなら出るかー」
「あれ、人いなくね?」
「やる人いないならやりますよー」
みたいなノリです。
安請け合いして今困ってる訳ですが…
なんか自分が適当過ぎて泣けてきた><


これ以上深く考えると欝になるので、そろそろ宣伝を
PyConJP2012はまだまだ色々なものを募集しています。

他にも、LTとか当日スタッフとかも募集予定です。
特にスタッフはまだまだ足りてないです。
こんな適当な僕でも色々と出来てるくらいなので
「大変なんでしょう?」
とか
「そんな志もないしなー」
なんて考えずに気軽に応募してください。

rediscoの利点と欠点と正しい使い方

はじめに
プロジェクトぽしゃって気力失ってたけど、どこかで誰かが使おうと思った時のために残しておく。

rediscoの使い方等は以下を参照
http://d.hatena.ne.jp/flag-boy/20110601/1306902308


rediscoの利点

1. Key-Valueじゃないデータ構造が扱いやすい
redisco とは RedisDjango モデルっぽく使えるようにしてくれるライブラリってだけあって、通常のKey-Valueじゃない構造が扱いやすくなっている。
特に、idを自動で振ってくれるのでkeyを自分で考える必要がない のは便利。

2. 検索がしやすい
普通のKey-Valueだとkeyが決まってないと値を取得出来ないため、条件に合うものを探し出すのとかは面倒。
その点rediscoはindexを張ってくれるので条件に合うものの取得が簡単。
複数の条件の組み合わせは不可だが、単一の条件であれば(例えば四角形の場合縦でも横でも)検索可能。


rediscoの欠点

遅い

当たり前っちゃ当たり前なんだけど、1つのモデルは複数のデータから出来ているので、その分遅い。
Djangoモデルと同じような感じで使おうとすると、redis使ってる意味ないじゃんってくらい遅くなる。
特にsave()が致命的に遅い。indexを更新してるからしょうがないんだけど。


rediscoの正しい使い方

indexの更新が重いならindexをなるべく張らないようにすれば何とかなるんじゃないかって?
そう思ってた時期が僕にもありました。
ところがそう単純ではなく、indexを張ってなくてもフィールドがあるだけで重くなる。
具体的にはindexを張ってないフィールドでもsave()一回につきwriteが2回走る。
結局軽くするにはフィールドを減らすしかないので、indexを張ってない(検索しない)フィールドはこんな風に1つにまとめる必要がある。

  • モデル定義
from redisco import models
class Animal(models.Model):                                                                                                                                                                                                                                                                                                                                                          
    animal_type = models.IntegerField(required=True)                                                                                                                                      
    area_id = models.IntegerField(required=True)                                                                                                                                            
    params_attr = redisco_models.Attribute(required=True,                                                                                                       
                                                                  default='', indexed=False)

params_attrはdictのpickleにして、検索しないものを全てここにまとめてある。
実際のプロダクションではsetterやgetter書いたりしてparams_attrの中をもっと使いやすくしてたけど、その辺は割愛。
こうすることでwriteの回数が減ってようやくマトモな速度で動くようになった。


まとめ
・redisを使って検索もしたいときとかは凄く便利
・というか他の用途で使うのはない
・使う場合は検索しないフィールドは極力減らす

PyConJPでスタッフしてました

せっかくだから何かお手伝いしたいなーってことで、
夏前からスタッフ登録をしてちょっとしたHPの修正とかをやってました。
当日はこんな格好で誘導したり

Partyの受付をしたりしてました。
大した事は出来なかったけど、次回もまたお手伝い出来たらなって思います。

rediscoのzfilter

前回zfilterは条件を1個しか指定出来ないよって書いたけど

Animal.objects.filter(area_id=1).zfilter(x__gte=1).zfilter(y__gte=1)

みたいにネストして書けば問題ないってことに一月以上経ってから気付いた。
ネストしたら一個目しか評価してなかった…今まで無駄なコード書いてたせいで処理が遅かったこともわかったし、なんつーか死にたい。

rediscoを使ってみた

rediscoって何?

redisco とは RedisDjango モデルっぽく使えるようにしてくれるライブラリ。
redis-py に依存している。
今回MySQLのTPSだと問題になりそうな処理がある & その処理にある程度複雑なモデルが必要だったので @ に教えてもらって使ってみた。

使い方

  • 接続
import redisco
redisco.connection_setup(host='localhost', port=6380, db=10)

保存や取得をする前には接続する必要がある。connection_setup を呼ぶことで redis との接続を作って保持してくれる。

  • モデル定義
from redisco import models
class AnimalType(models.Model):
    name = models.Attribute(required=True)

class Animal(models.Model):
    name = models.Attribute(required=True, indexed=False)
    animal_type = models. ReferenceField(AnimalType, required=True)
    created_at = models.DateTimeField(auto_now_add=True)
    coord_x = models.IntegerField(equired=True, indexed=False)
    coord_y = models.IntegerField(equired=True, indexed=False)

こんな感じでモデルを作れる。
Django と比べると
CharField -> Attribute
ForienKey -> ReferenceField
になってるのが主な違い。

  • 保存
cat = Animal.objects.create(name=u'ネコ')
animal = Animal()
animal.name = u'タマ'
animal.type = cat
animal.coord_x = 1
animal.coord_y = 1
animal.save()

オブジェクトを作って保存する方法は Djangoモデルと同じ。
保存時に Django と同じように id を作ってくれる。
ただし id が int じゃなく数値文字列('10'とか)なので注意。

  • 取得

普通に取って来るだけなら(遅延評価してるとこも含めて) Django と変わらない。(get はないっぽいけど)

cats_query = AnimalType.objects.filter(name=u'ネコ')

cats = cats_query.members
# これも同じ
cats = list(cats_query)

cats_count = len(cats_query)

cat = cats_query.first()
# これも同じ
cat = cats_query[0]


ただ、indexd=False なフィールドを条件に指定することは出来ない。デフォルトが index=True なので、絶対に条件に指定しないフィールド以外は index=False にしないこと推奨。

# これはOKだけど
animal = Animal.objects.filter(animal_type=cat)[0]
# これはエラー
tama = Animal.objects.filter(name=u'タマ')[0]


また、filter() では id を条件に指定することは出来ないので、id で引きたい場合は、get_by_id() を使う。

# これはエラーなので
animal = Animal.objects.filter(id=1)[0]
# こっちを使う
# tama.id は str だけど、ここに指定するのは int でOK
tama = Animal.objects.get_by_id(1)


Djangoみたいに __in とか __lte とかも使える。その場合は filter() の代わりに zfilter() を使う。ただ、zfilter() だと list() で評価は出来ないし、複数の条件も指定出来ない。

# これは出来るけど
animals_query = Animal.objects.zfilter(created_at__lte=datetime.datetime.now())
# これは出来ない
cats_query = Animal.objects.zfilter(created_at__lte=datetime.datetime.now(), animal_type=cat)

# これは出来るけど
animals = animals_query.member
animals.count = len(animals_query.member)
animal = animals_query.member[0]
# これは出来ない
animals = list(animals_query)
animals = len(animals_query)
animal = animals_query[0]


使ってみた感想
redisco を使うと、保存時に自動的にトランザクションを使ってくれるし key を自分で考えたりせずに使えるので非常に楽だった。
ただしDjangoモデルとは微妙に違うし、ドキュメント少ない上に日本語のものは皆無なのでソースを追ったりする必要があったのが面倒。
今回は使ってないけど、Djangoモデルっぽいもの以外に Set とかも作れるので単純な Key-Value の用途以外で使う場合は検討してみる価値が十分にあると思う。