Рекурсивно делать путь из кэша Django
Я удаляю один путь из кэша Django следующим образом:
from models import Graph
from django.http import HttpRequest
from django.utils.cache import get_cache_key
from django.db.models.signals import post_save
from django.core.cache import cache
def expire_page(path):
request = HttpRequest()
request.path = path
key = get_cache_key(request)
if cache.has_key(key):
cache.delete(key)
def invalidate_cache(sender, instance, **kwargs):
expire_page(instance.get_absolute_url())
post_save.connect(invalidate_cache, sender = Graph)
Это работает - но есть ли способ удалить рекурсивно? Мои пути выглядят так:
/graph/123 /graph/123/2009-08-01/2009-10-21
Всякий раз, когда граф с идентификатором "123" сохраняется, кэш для обоих путей должен быть аннулирован. Можно ли это сделать?
3 ответа
Возможно, вы захотите использовать стратегию кеширования поколений, похоже, она будет соответствовать тому, что вы пытаетесь достичь. В коде, который вы предоставили, вы должны хранить номер "поколения" для каждого абсолютного URL. Так, например, вы должны инициализировать "/graph/123" для генерации единицы, а затем его ключ кеша станет чем-то вроде "/GENERATION/1/graph/123". Когда вы хотите истечь срок действия кэша для этого абсолютного URL, вы увеличиваете его значение генерации (в этом случае до двух). Таким образом, в следующий раз, когда кто-то отправится искать "/graph/123", ключ кеша станет "/GENERATION/2/graph/123". Это также решает проблему истечения срока действия всех подстраниц, поскольку они должны ссылаться на тот же ключ кеша, что и "/graph/123".
Сначала это немного сложно понять, но это действительно элегантная стратегия кэширования, которая, если все сделано правильно, означает, что вам никогда не придется ничего удалять из кэша. Для получения дополнительной информации здесь представлена презентация о кешировании поколений, это для Rails, но концепция одна и та же, независимо от языка.
Другой вариант - использовать кеш, который поддерживает тегирование ключей и удаление ключей по тегу. API встроенного кэша в Django не поддерживает этот подход. Но, по крайней мере, один кеш-сервер (не являющийся частью Django) имеет поддержку.
DiskCache* - это лицензированная Apache2 библиотека дискового и файлового кэша, написанная на чистом Python и совместимая с Django. Чтобы использовать DiskCache в своем проекте, просто установите его и настройте CACHES
установка.
Установка проста с pip
:
$ pip install diskcache
Затем настройте свой CACHES
установка:
CACHES = {
'default': {
'BACKEND': 'diskcache.DjangoCache',
'LOCATION': '/tmp/path/to/directory/',
}
}
Кеш set
метод расширен необязательным tag
Ключевое слово аргумент так:
from django.core.cache import cache
cache.set('/graph/123', value, tag='/graph/123')
cache.set('/graph/123/2009-08-01/2009-10-21', other_value, tag='/graph/123')
diskcache.DjangoCache внутренне использует diskcache.FanoutCache. Соответствующий FanoutCache доступен через _cache
атрибут и выставляет evict
метод. Чтобы выселить все ключи, помеченные /graph/123
просто:
cache._cache.evict('/graph/123')
Хотя доступ к атрибуту с префиксом подчеркивания может показаться неудобным, проект DiskCache стабилен и вряд ли внесет значительные изменения в DjangoCache
реализация.
На странице тестов кеша Django обсуждаются альтернативные механизмы кеширования.
- Отказ от ответственности: я являюсь первоначальным автором проекта DiskCache.
Оформить заказ shutils.rmtree() или os.removedirs (). Я думаю, что первое, вероятно, то, что вы хотите.
Обновление основано на нескольких комментариях: На самом деле механизм кэширования Django является более общим и более тонким, чем просто использование path
для ключа (хотя вы можете использовать его на этом уровне). У нас есть несколько страниц с 7 или 8 отдельно кэшированными подкомпонентами, срок действия которых истекает на основе ряда критериев. Наши имена кэша компонентов отражают ключевые объекты (или классы объектов) и используются для определения того, что должно быть признано недействительным при определенных обновлениях.
Все наши страницы имеют общий ключ кеша, основанный на статусе участника / не участника, но это только около 95% страницы. Остальные 5% могут меняться для каждого члена и поэтому не кэшируются вообще.
То, как вы перебираете свой кеш для поиска недопустимых элементов, зависит от того, как он на самом деле хранится. Если это файлы, вы можете использовать просто глобусы и / или рекурсивные удаления каталогов, если это какой-то другой механизм, вам придется использовать что-то другое.
Мой ответ и некоторые комментарии других пытаются сказать, что то, как вы выполняете аннулирование кэша, тесно связано с тем, как вы используете / храните кэш.
Второе обновление: @andybak: Итак, я полагаю, ваш комментарий означает, что все мои коммерческие сайты Django взорвутся? Спасибо за внимание к этому. Я заметил, что вы не пытались ответить на проблему.
Проблема Knipknap состоит в том, что у него есть группа элементов кэша, которые кажутся связанными и находятся в иерархии из-за их имен, но логика генерации ключа механизма кэширования стирает это имя, создавая MD5-хэш пути + var_on. Поскольку в исходном пути / параметрах нет никаких следов, вам придется тщательно угадывать все возможные комбинации путей / параметров, надеясь, что вы сможете найти правильную группу. У меня есть другие увлечения, которые более интересны.
Если вы хотите иметь возможность находить группы кэшированных элементов на основе некоторой комбинации значений пути и / или параметров, вы должны либо использовать ключи кэша, которые могут быть сопоставлены с шаблоном напрямую, либо какая-либо система, которая сохраняет эту информацию для использования во время поиска.
Поскольку у нас были потребности, не связанные с проблемой OP, мы взяли на себя управление кэшированием фрагментов шаблона - и особенно генерацией ключей - более 2 лет назад. Это позволяет нам использовать регулярные выражения несколькими способами, чтобы эффективно аннулировать группы связанных кэшированных элементов. Мы также добавили время ожидания по умолчанию и имена переменных var_on (разрешаются во время выполнения), которые можно настроить в settings.py
изменил порядок имен и тайм-аутов, потому что не имело смысла всегда переопределять тайм-аут по умолчанию для именования фрагмента, сделал имя_фрагмента разрешаемым (т. е. это может быть переменная) для лучшей работы с многоуровневым шаблоном схема наследования и еще несколько вещей.
Единственная причина моего первоначального ответа, который был действительно неправильным для нынешнего Django, заключалась в том, что я так долго использовал ключи кэш-памяти saner, что буквально забыл простой механизм, от которого мы отказались.