如何使django中的@cached_property失效
我现在在一个模型类上使用 @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 个回答
如果你不想用 try
和 except
,而且想写更少的代码,可以使用:
if ("expensive_property" in obj.__dict__):
del obj.expensive_property
或者:
if ("expensive_property" in obj.__dict__):
delattr(obj, "expensive_property")
这样做会删除缓存的属性,下次访问时会重新计算这个属性。
更新:不要使用 if (hasattr(obj, "expensive_property")):
!这样做会在属性还没被缓存的时候就计算它,并且总是返回 True
!
由于正在开发中,这里进行了大量编辑... 现在支持为给定的缓存属性使用多个标签。
我遇到了类似的问题,我有一组相关的 cached_property
对象,它们都需要同时失效。我是这样解决的:
扩展
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)
在我的其他对象中,使用我新的
cached_property.tag
装饰器类方法来定义带标签的cached_property
方法:@cached_property.tag("foo_group") def foo(self): return "foo"
在使用新装饰器的对象上,写一个方法,通过遍历实例化对象的类的
__dict__
来使所有带有指定标签的cached_property
值失效。这可以防止意外调用所有的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)
现在,要使其失效,我只需调用 myobject.invalidate("foo_group")
。
我创建了一个Django模型的混合类,这个混合类的作用是当调用model.refresh_from_db()
时,会使模型上所有的@cached_property
属性失效。你也可以通过调用model.invalidate_cached_properties()
手动使缓存的属性失效。
from django.utils.functional import cached_property
class InvalidateCachedPropertiesMixin():
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的回答启发的。
就像文档里说的那样,直接用 del 来删除它。这会导致下次访问时重新计算。
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
在Python 3中,使用 del
的方法是一样的。下面是一个 try/except 块的例子。
try:
del obj.expensive_property
except AttributeError:
pass