DjangoのForeinKeyとかキャッシュとか

キャッシュ機能付きモデルの欠点

以前、Djangoでキャッシュ機能付きモデル - ま、そんな日もあるさを書いたんですけど、これって ForeinKey を持つようなモデルだと思ったように上手く動いてくれません。

class Community(AbustractCachedModel):
    name = models.CharField(max_length=50)

class Player(AbustractCachedModel):
    name = models.CharField(max_length=50)
    community = models.ForeinKey(Community)

みたいな、モデルがあった時に

player = Player.get(1)
player.community

みたいにアクセスしてしまうとキャッシュから読むのではなく SQL が発行されてしまいます。


解決策

そういう場合は

class Player(AbustractCachedModel):
    name = models.CharField(max_length=50)
    community = models.ForeinKey(Community)

    @property
    def cached_community(self):
        return Community.get(self.community_id) 

みたいにプロパティを定義して

player = Player.get(1)
player.cached_community

みたいなアクセスをすれば OK です。
ここで使っている community_id は Django で ForeinKey なフィールドを作った時に実際のテーブルに追加されるフィールド名です。(フィールド名が xxx だったら xxx_id になります)


もうちょい詳しい話

player.community

みたいなアクセスの場合(実際には Django 内部のキャッシュとか色々ありますが)簡略化すると以下のような処理が走るので SQL が発行されてしまいます。

Player.objects.get(id=player.community_id)

なので、player を取得した時点でわかっている community_id を使ってキャッシュからアクセスすることで、SQL を発行せずに community を取得することが可能になります。
なお、community の代わりに community_id を使って SQL の発行回数を減らすノウハウは結構使うので覚えておくと良いかもしれません。