2009-10-06 7 views
13

UserProfileオブジェクトにJSONオブジェクトを含む複数のTextField列があります。また、JSONをPythonデータ構造にシリアライズおよびデシリアライズするためのロジックをカプセル化する各列のsetter/getterプロパティを定義しました。Djangoモデルオブジェクトの高価な計算をどのようにメモしますか?

このデータの性質上、単一のリクエスト内でビューロジックとテンプレートロジックによって何度もアクセスされることが保証されています。デシリアライゼーションコストを節約するために、私は読み込み時にpythonデータ構造をメモし、プロパティへの直接書き込みで無効にしたり、モデルオブジェクトからの信号を保存したりしたいと思います。

どこにメモを保存しますか?特定のUserProfileがクエリによってどのようにインスタンス化されているかの背後にある魔法を理解していないので、インスタンス変数を使用することについては心配です。 __init__を安全に使用していますか、またはそれぞれの読み取り時にhasattr()経由でメモ属性の有無を確認する必要がありますか?ここで

は私の現在の実装の例です:

def get_expensive_operation(self): 
    if not hasattr(self, '_expensive_operation'): 
     self._expensive_operation = self.expensive_operation() 
    return self._expensive_operation 

次にあなたがデータにアクセスするためのget_expensive_operationメソッドを使用します。一般的に

class UserProfile(Model): 
    text_json = models.TextField(default=text_defaults) 

    @property 
    def text(self): 
     if not hasattr(self, "text_memo"): 
      self.text_memo = None 
     self.text_memo = self.text_memo or simplejson.loads(self.text_json) 
     return self.text_memo 
    @text.setter 
    def text(self, value=None): 
     self.text_memo = None 
     self.text_json = simplejson.dumps(value) 

答えて

23

組み込みのdjangoデコレータdjango.utils.functional.memoizeに興味があるかもしれません。

Djangoはこれを使用して、URL解決のような高価な操作をキャッシュします。

+0

これは知っておきたいことです。ありがとう。 –

+16

クラスメソッドの場合は、 'django.utils.functional.cached_property'を使用することをお勧めします。クラスメソッドの最初の引数は 'self'なので、memoizeはそれを投げ捨ててもオブジェクトと関数の結果への参照を保持します。ガベージコレクタが失効したオブジェクトをクリーンアップしないようにすることで、メモリリークを引き起こす可能性があります。 'cached_property'はダニエルの提案をデコレータに変換します。 – Arion

+0

アリオン、これはまさに私が探していたものです:-) – pstadler

16

、私はこのようなパターンを使用します。

しかし、あなたの特定のケースでは、私はあなたがこれをやや間違った方法で近づいていると思います。モデルがデータベースから最初にロードされたときに非直列化を実行し、保存時にのみ直列化する必要があります。その後、毎回標準のPython辞書として属性にアクセスすることができます。これを行うには、カスタムJSONFieldタイプを定義し、to_pythonget_db_prep_saveをオーバーライドするmodels.TextFieldをサブクラス化します。

実際に誰かが既にそれを行っています:hereを参照してください。

+0

あなたは完全に正しいです。私たちはすでに辞書を受け取って操作してから、それをセッターに返さなければならないということに、すでに悩んでいました。辞書を適切に操作する方がはるかに良いです。 JSONフィールドの実装は興味深いですが、私はそれが裏でどのように動作するのかは不明です。それは、ロード時に一度逆シリアル化され、操作可能なPythonオブジェクトを提供します。次に、保存時に再びシリアル化されますか? –

+0

はい、正確です。その間に、それは普通の辞書です。 –

1

クラスメソッドについては、django.utils.functional.cached_propertyを使用してください。

クラスメソッドの最初の引数がselfであるため、オブジェクトを投げ捨ててもオブジェクトとその関数の参照への参照が維持されます。ガベージコレクタが失効したオブジェクトをクリーンアップしないようにすることで、メモリリークを引き起こす可能性があります。 cached_propertyはダニエルの提案をデコレータに変えます。

+0

これは受け入れられる回答でなければなりません。 – mrts

関連する問題