Как я могу аннулировать @cached_property в django

Привет всем, я в настоящее время использую @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

благодаря

Ответ 1

Просто, как говорится в документации. Это приведет к перерасчету при следующем доступе.

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

Ответ 2

Отредактировано в значительной степени из-за продолжающейся разработки... Теперь поддерживает несколько тегов для данного кеша_property.

Я столкнулся с аналогичной проблемой, в которой у меня был набор связанных объектов cached_property которые потребовали одновременной аннулирования. Я решил это так:

  1. Расширьте cached_property чтобы принять значения тегов и включить класс класса decorator:

    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 decorator cached_property.tag для определения cached_property методов cached_property:

    @cached_property.tag("foo_group")
    def foo(self):
        return "foo"
    
  3. На моем объекте, который использует новый декоратор, напишите метод, чтобы аннулировать все значения cached_property с помощью именованного тега, __dict__ по __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)
    

Теперь, чтобы сделать недействительным, я просто myobject.invalidate("foo_group").

Ответ 3

Я создал модель Django mixin, которая отменяет все свойства @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

Вдохновленный Томасом Баденом ответ.