※ 商品のリンクをクリックして何かを購入すると私に少額の報酬が入ることがあります【広告表示】 monologista がオープンソース化されようとしています。
monologistaは、昨年の5月にpateoさんが作って運用しているつぶやき系のwebアプリケーションです。pateoさんはプログラムも書きますが、本 職はデザイナさんなのでデザインも素敵です。
Djangoのtrunkで動くようにしてからオープンソース化するとのことで、Djangoのサンプルとしても、社内とかで使うつぶやきWebアプリとしても、期 待大なのです。
今、コードを直しつつブログでノウハウを公開されているところですが、丁度拙作の Tracka でも気になっているタイムライン(自分と、自分がフォローしている人の投稿が一覧されるもの)部分について言及されていたので、少し考えてみました。
pateoさんは、 タイムラインの生成にQオブジェクトを使って OR を組み立てている ようです。
実のところ、SQLには文字列の長さ制限がありますので、大量にORをつなぐと実行時にエラーとなってしまいます。と、いいながら現在Trackaも IN を使っているだけなので微妙に長さが伸びに勢いがないだけで同様の問題を抱えています。
friends = Friend.objects.filter(me__exact=request.user.id).select_related()
friends_id = [f.favorit_id for f in friends] + [request.user.id] #手抜き
Track.objects.filter(tracker__id__in=friends_id).order_by('-created')
Trackaでは、あえてManyToManyFieldを使用せずにUserに対してForeignKeyを二つもったモデルを定義しています。DjangoではManyToManyの関連で利用される中間テーブルはPythonコード側から見えないため、ゴリゴリやりたいときのためにそうしています。
実際のところ、Trackaの場合はこんな感じにすればフォローしている人の数に関わりなく同じSQLになります(まだ検証していないけど…meじゃなくってfavoriteかも…)。
Track.objects.filter(Q(tracker__id=request.user.id) |
Q(tracker__friend__me=request.user.id)).order_by('-created')
#trackerはTrack(Postみたいの)を投稿したユーザ
#friendはフォロー関係を表す中間テーブル
#meは中間テーブルでフォローしているユーザ(つまり自分)
大規模になると話は変わってくると思いますが、ある程度まではこの位の気の使い方でいいんじゃないかと思います。