如何在django中使@cached_property无效

时间:2014-05-06 08:23:57

标签: django django-models django-views

大家好我当前正在模型类上使用@cached_property并且不喜欢在保存时将其删除,以便在下次调用时可以重新填充它如何执行此操作。 例如:

class Amodel():
    #...model_fields....

    @cached_property
    def db_connection(self):
        #get some thing in the db and cache here


instance = Amodel.objects.get(id=1)
variable = instance.db_connection

Amodel.objects.select_for_update().filter(id=1).update(#some variable)
#invalidate instance.db_connection
#new_variable = instance.db_connection

由于

4 个答案:

答案 0 :(得分:37)

将其作为文档says。这将导致下次访问时重新计算。

class SomeClass(object):

    @cached_property
    def expensive_property(self):
         return datetime.now()

obj = SomeClass()
print obj.expensive_property
print obj.expensive_property # outputs the same value as before
del obj.expensive_property
print obj.expensive_property # outputs new value

答案 1 :(得分:5)

由于正在进行的开发而严重编辑...现在支持给定cached_property的多个标记。

我遇到了类似的问题,其中我有一组相关的cached_property对象,这些对象都需要同时失效。我以这种方式解决了它:

  1. 扩展cached_property以接受标记值并包含装饰器类方法:

    def __init__(self, func, *tags):
        self.func = func
        self.tags = frozenset(tags)
    
    @classmethod
    def tag(cls *tags):
        return lambda f: cls(f, *tags)
    
  2. 在我的其他对象中,使用我的新cached_property.tag装饰器类方法来定义标记的cached_property方法:

    @cached_property.tag("foo_group")
    def foo(self):
        return "foo"
    
  3. 在我使用新装饰器的对象上,通过遍历实例化对象类的cached_property编写一个方法,使所有__dict__值与命名标记无效。这可以防止意外调用所有cached_property方法:

    def invalidate(self, tag):
        for key, value in self.__class__.__dict__.items():
            if isinstance(value, cached_property) and tag in value.tags:
                self.__dict__.pop(key, None)
    
  4. 现在,为了宣告无效,我只是调用myobject.invalidate("foo_group")

答案 2 :(得分:4)

我创建了一个Django模型混合,当调用@cached_property时,该模型上的所有model.refresh_from_db()属性都无效。您也可以使用model.invalidate_cached_properties()使缓存的属性无效。

from django.utils.functional import cached_property


class RefreshFromDbInvalidatesCachedPropertiesMixin():

    def refresh_from_db(self, *args, **kwargs):
        self.invalidate_cached_properties()
        return super().refresh_from_db(*args, **kwargs)

    def invalidate_cached_properties(self):
        for key, value in self.__class__.__dict__.items():
            if isinstance(value, cached_property):
                self.__dict__.pop(key, None)

https://gitlab.com/snippets/1747035

Thomas Baden的回答启发。

答案 3 :(得分:3)

如果您不想使用tryexcept,并且不想写太多行,则可以使用:

if hasattr(obj, "expensive_property"):
    delattr(obj, "expensive_property")

或者:

if hasattr(obj, "expensive_property"):
    del obj.expensive_property

它将删除缓存的属性,下次访问该属性时将再次计算。