2009-10-06 76 views
13

我的UserProfile對象上有幾個包含JSON對象的TextField列。我還爲每列定義了setter/getter屬性,它封裝了將JSON序列化和反序列化爲Python數據結構的邏輯。如何在Django模型對象上記憶昂貴的計算?

這些數據的性質確保它可以在單個請求中被查看和模板邏輯多次訪問。爲了節省反序列化成本,我想在讀取時記憶python數據結構,直接寫入屬性或從模型對象保存信號時失效。

Where /如何存儲備忘錄?我對使用實例變量感到緊張,因爲我不明白任何特定的UserProfile如何通過查詢實例化。 __init__可以安全使用,還是我需要通過hasattr()在每次閱讀時檢查是否存在備忘屬性?

這是我目前執行的一個例子:

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

這很好理解。謝謝。 – 2010-04-14 13:21:33

+16

對於類方法,我更喜歡使用'django.utils.functional.cached_property'。由於類方法的第一個參數是'self',因此memoize將保留對該對象和函數結果的引用,即使在拋出它之後。這可以通過阻止垃圾收集器清除過時對象來導致內存泄漏。 'cached_property'將丹尼爾的建議變成了一個裝飾器。 – Arion 2012-07-12 18:05:24

+0

Arion,這正是我所尋找的:-) – pstadler 2012-07-24 12:35:38

16

一般情況下,我使用的模式是這樣的:

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

然後使用get_expensive_operation方法來訪問數據。

但是,在您的具體情況下,我認爲您以稍微錯誤的方式來解決這個問題。首次從數據庫加載模型時需要執行反序列化,並在保存時序列化。然後你可以簡單地訪問屬性作爲標準的Python字典。您可以通過定義一個自定義JSONField類型來執行此操作,將models.TextField進行子類化,這會覆蓋to_pythonget_db_prep_save

實際上有人已經這樣做了:請參閱here

+0

你完全正確。我們已經厭煩了,我們必須收到字典,操縱它,然後將它發回給制定者。操作字典的地方更好。 JSON字段的實現很有趣,但我不確定它是如何在幕後工作的。它在加載時是否反序列化,提供一個可操縱的python對象,然後再保存序列化呢? – 2009-10-06 18:44:26

+0

是的,確切地說。在這之間,這是一個正常的字典。 – 2009-10-06 19:26:05

1

對於類方法,您應該使用django.utils.functional.cached_property

由於類方法的第一個參數是self,memoize將保留對該對象和該函數結果的引用,即使在將其拋出後也是如此。這可以通過阻止垃圾收集器清除過時對象來導致內存泄漏。 cached_property把丹尼爾的建議變成了裝飾者。

+0

這應該是被接受的答案。 – mrts 2017-10-16 08:03:38

相關問題