如何使Django中的@cached_属性无效

2024-04-23 15:12:27 发布

您现在位置:Python中文网/ 问答频道 /正文

我目前正在一个模型类上使用@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

谢谢


Tags: instance模型iddbgetmodelobjectsupdate
3条回答

我创建了一个Django模型mixin,当调用model.refresh_from_db()时,它会使模型上的所有@cached_property属性失效。也可以使用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的答案启发

只需将其删除为文档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

对于Python3,它与del的用法相同。下面是try/except块的示例

try:
    del obj.expensive_property 
except AttributeError:
    pass 

由于正在进行的开发,大量编辑。。。现在支持给定缓存的属性的多个标记

我遇到了一个类似的问题,其中我有一组相关的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. 在使用新decorator的对象上,编写一个方法,通过遍历实例化对象类的__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")

相关问题 更多 >