Сообщить об ошибке.

Расширение Flask-Caching для приложения Flask в Python

Кэширование бэкендов в приложениях Flask

Модуль Flask-Caching представляет собой расширение для фреймворка Flask, которое добавляет поддержку кэширования для различных бэкендов в любое приложение Flask. Начиная с версии Flask-Caching 1.8, кэширование Flask поддерживает только Python 3.5+.

Модуль кэширования Flask-Caching устанавливается с помощью следующей команды:

$ python -m pip install -U Flask-Caching

Содержание:


Подключение расширения Flask-Caching в приложение Flask.

Управление кэшем осуществляется через экземпляр кэша:

from flask import Flask
from flask_caching import Cache

config = {
    # режим отладки Flask
    "DEBUG": True,
    # тип кэширования Flask-Caching
    "CACHE_TYPE": "SimpleCache",
    # время кэширования по умолчанию
    "CACHE_DEFAULT_TIMEOUT": 300
}
app = Flask(__name__)
# применяем указанную выше конфигурацию
app.config.from_mapping(config)
# создаем экземпляр кэша
cache = Cache(app)

Можно также настроить экземпляр кэша позже, используя метод экземпляра кэша cache.init_app():

cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})

app = Flask(__name__)
cache.init_app(app)

Можно предоставить альтернативный словарь конфигурации, что полезно, если будет несколько экземпляров кэша, каждый из которых будет иметь другую внутреннюю часть:

# во время создания экземпляра кэша
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})
# во время вызова `init_app`
cache.init_app(app, config={'CACHE_TYPE': 'simple'})

Кэширование функций-представлений в приложении Flask.

Для кэширования функций-представлений, необходимо использовать декоратор @cache.cached(). Этот декоратор, по умолчанию для ключа cache_key будет использовать request.path:

@app.route("/")
@cache.cached(timeout=50)
def index():
    return render_template('index.html')

У кэшированного декоратора @cache.cached() есть еще один необязательный аргумент, называемый unless. Этот аргумент принимает вызываемый объект, который должен возвращать значение True или False. Если функция, переданная в unless возвращает значение True, то механизм кэширования будет полностью отключатся.

Предупреждение: При использовании кэширования в функции-представлении необходимо размещать @cache.cached() между декоратором @app.route() и определением функции-представления. Например:

@app.route('/')
@cache.cached(timeout=50)
def index():
    return 'Cached for 50s'

Кэширование других функций в приложении Flask.

Используя тот же декоратор @cache.cached(), можно кэшировать возвращаемые результаты других функций, не связанных с просмотром страниц сайта. При кэшировании результатов простых функций необходимо изменять аргумент key_prefix , т.к. по умолчанию кеширующий декоратор будет использовать request.path для cache_key. Ключи управляют тем, что должно быть извлечено из кэша. Работает это следующим образом: если в кэше, ключ cache_key не существует, то будет создана новая запись key-value. В противном случае будет возвращено значение, соответствующее cache_key (т. е. кэшированный результат):

@cache.cached(timeout=50, key_prefix='all_comments')
def get_all_comments():
    comments = do_serious_dbio()
    return [x.author for x in comments]

cached_comments = get_all_comments()

Хранение кэшированных значений в памяти сервера.

При использовании кэширующего декоратора @cache.memoize(), в качестве ключа cache_key будут использоваться аргументы, принимаемые функцией, результат которой будет храниться в памяти сервера.

Примечание: Декораторы @cache.cached() и @cache.memoize() фактически одинаковы, если не получают аргументы.

Декоратор @cache.memoize() также предназначен для методов классов, так как он будет учитывать индификатор аргумента self или cls как части ключа кэша.

Декоратор @cache.memoize() работает следующим образом: если есть функция, которую нужно вызвать несколько раз в одном запросе, она будет вычислена только при первом вызове этой функции с конкретными аргументами. Например, объект sqlalchemy, который вычисляет какие-то параметры пользователя, возможно придется использовать много раз во время одного запроса. Чтобы каждый раз не обращаться к базе данных, можно сделать что-то вроде этого:

class Person(db.Model):
    @cache.memoize(50)
    def has_membership(self, role_id):
        return Group.query.filter_by(user=self, role_id=role_id).count() >= 1

Предупреждение. Использование изменяемых объектов (классов и т.д.), в качестве части ключа кэша может быть сложным. Рекомендуется не передавать экземпляр объекта в кэшируемую функцию. Декоратор @cache.memoize использует функцию repr() для просмотра переданных аргументов, так что, если у объекта есть метод __repr__, который возвращает уникально идентифицирующую строку для этого объекта, то она будет использоваться как часть ключа кэша.

Например, можно создать класс Person объекта sqlalchemy, который будет возвращать идентификатор базы данных, как часть уникального идентификатора:

class Person(db.Model):
    def __repr__(self):
        return f'self.__class__.__name__(self.id)'

Удаление кэша из памяти сервера.

Возможно, потребуется удалить кэш для какой-то функции. Используя приведенный выше пример, предположим, что пользователь редактировал свой профиль или ему была назначена другая роль и теперь необходимо пересчитать кэшированные значения. Это можно сделать с помощью метода cache.delete_memoized() :

cache.delete_memoized(user_has_membership)

Примечание. Если в качестве аргумента указано только имя функции, все сохраненные версии кэша будут признаны недействительными. Однако можно удалить только определенный кэш, для этого нужно передать те же значения аргументов, что и при кэшировании. В следующем примере удаляется только кэш 'user':

# кэширование значений из базы для `'admin'` и `'user'`
user_has_membership('demo', 'admin')
user_has_membership('demo', 'user')
# удаляется только кэш `'user'`
cache.delete_memoized(user_has_membership, 'demo', 'user')

Предупреждение. Если в памяти сохранен метод класса, то необходимо указать сам класс в качестве аргумента.

class Foobar(object):
    @classmethod
    @cache.memoize(5)
    def big_foo(cls, a, b):
        return a + b + random.randrange(0, 100000)

cache.delete_memoized(Foobar.big_foo, Foobar, 5, 2)

Кэширующий сниппет для шаблонов Jinja2 приложения Flask.

Зразу начнем с примера использования кэширующего сниппета:

{% cache [timeout [,[key1, [key2, ...]]]] %}
...
{% endcache %}

По умолчанию, в качестве ключа кэша используется значение "путь к файлу шаблона" + "начальная строка блока". Кроме того, имя ключа можно задать вручную. Ключи объединяются в одну строку, которую можно использовать для исключения вычисления одного и того же блока в разных шаблонах.

Чтобы кэш хранился постоянно, нужно установить для timeout значение None, но с настраиваемыми ключами:

{% cache None, "key" %}
...
{% endcache %}

Чтобы удалить кэшированное значение, нужно установить для timeout значение 'del',

{% cache 'del', key1 %}
...
{% endcache %}

Если в кеширующий сниппет переданы ключи, то можно легко сгенерировать ключ фрагмента шаблона и удалить его вне контекста шаблона:

from flask_caching import make_template_fragment_key
key = make_template_fragment_key("key1", vary_on=["key2", "key3"])
cache.delete(key)

Если в шаблонах Flask используются макросы, которые например генерируют форму, то можно закэшировать ее следующим образом:

{% cache 60*5 %}
<div>
    <form>
    {% render_form_field(form.username) %}
    {% render_submit() %}
    </form>
</div>
{% endcache %}

Очистка кэша cache.clear().

Пример сценария для полной очистки кэша приложения Flask:

from flask_caching import Cache
from yourapp import app, your_cache_config

cache = Cache()

def main():
    cache.init_app(app, config=your_cache_config)

    with app.app_context():
        cache.clear()

if __name__ == '__main__':
    main()

Предупреждение. Некоторые серверные реализации не поддерживают полную очистку кэша. Кроме того, если не использовать префикс ключа, то некоторые реализации (например, Redis) очистят всю базу данных. Перед полной очисткой кэша необходимо убедиться, что в базе данных кэширования не хранятся другие данные.

Явное кэширование данных.

Данные могут быть кэшированы явно с помощью прокси-методов, таких как Cache.set() и Cache.get().

Например:

@app.route("/html")
@app.route("/html/<foo>")
def html(foo=None):
    if foo is not None:
        cache.set("foo", foo)
    bar = cache.get("foo")
    return render_template_string(
        "<html><body>foo cache: {{bar}}</body></html>", bar=bar
    )

Список параметров конфигурации, используемых Flask-Caching.

  • CACHE_TYPE: Указывает, какой тип объекта кэширования следует использовать. Это строка, которая будет импортирована. Предполагается, что объект импорта - это функция, которая вернет объект кэша, соответствующий API кэша.

    Список встроенных объектов кэширования:

  • CACHE_NO_NULL_WARNING: Silence the warning message when using cache type of ‘null’.

  • CACHE_ARGS: Необязательный список для распаковки и передачи во время создания экземпляра кэша.

  • CACHE_OPTIONS: Необязательный словарь для передачи во время создания экземпляра кэша.

  • CACHE_DEFAULT_TIMEOUT: Тайм-аут в секундах по умолчанию, который будет использоваться в @cache.cached, если тайм-аут не указывается явно.

  • CACHE_IGNORE_ERRORS: Если установлено значение True, то любые ошибки, возникшие во время процесса удаления, будут проигнорированы. Если установлено значение False, то процесс удаления остановится при возникновении первой ошибки. Эта опция актуальна только для бэкэндов 'FileSystemCache' и 'SimpleCache'. По умолчанию установлено значение False.

  • CACHE_THRESHOLD: Максимальное количество элементов, которые будут храниться в кэше, прежде чем он начнет удалять некоторые из них. Используется только для SimpleCache and FileSystemCache.

  • CACHE_KEY_PREFIX: Префикс, добавляемый перед всеми ключами. Это позволяет использовать один и тот же сервер memcached для разных приложений. Используется только для RedisCache и MemcachedCache.

  • CACHE_SOURCE_CHECK: Условие по умолчанию, применяемое к декораторам функций, которое определяет, следует ли включать исходный код функции при формировании хэша, используемого в качестве ключа кэша. Это гарантирует, что при изменении исходного кода кэшированное значение не будет возвращено при вызове новой функции, даже если аргументы совпадают. По умолчанию установлено значение False.

  • CACHE_UWSGI_NAME: Имя экземпляра uwsgi для подключения, например: mycache@localhost:3031, по умолчанию используется пустая строка, что означает, что uWSGI будет кэшироваться в локальном экземпляре. Если кэш находится в том же экземпляре, что и приложение werkzeug, то нужно указать только имя кэша.

  • CACHE_MEMCACHED_SERVERS: Список или кортеж адресов серверов. Используется только для MemcachedCache.

  • CACHE_MEMCACHED_USERNAME: Имя пользователя для аутентификации SASL с помощью memcached. Используется только для SASLMemcachedCache.

  • CACHE_MEMCACHED_PASSWORD: Пароль для аутентификации SASL с помощью memcached. Используется только для SASLMemcachedCache.

  • CACHE_REDIS_HOST: Хост сервера Redis. Используется только для RedisCache.

  • CACHE_REDIS_PORT: Порт сервера Redis. Значение по умолчанию 6379. Используется только для RedisCache.

  • CACHE_REDIS_PASSWORD: Пароль Redis для сервера. Используется только для RedisCache и RedisSentinelCache.

  • CACHE_REDIS_DB: База данных Redis (индекс чисел на основе нуля). Значение по умолчанию равно 0. Используется только для RedisCache и RedisSentinelCache.

  • CACHE_REDIS_SENTINELS: Список или кортеж адресов Redis Sentinel. Используется только для RedisSentinelCache.

  • CACHE_REDIS_SENTINEL_MASTER: Имя главного сервера в конфигурации Sentinel. Используется только для RedisSentinelCache.

  • CACHE_REDIS_CLUSTER: Строка адресов узлов кластера Redis, разделенных запятыми. Например host1:port1,host2:port2,host3:port3 . Используется только для RedisClusterCache.

  • CACHE_DIR: Каталог для хранения кэша. Используется только для FileSystemCache.

  • CACHE_REDIS_URL: URL-адрес для подключения к серверу Redis. Пример redis://user:password@localhost:6379/2. Поддерживает протоколы redis://, rediss:// (redis через TLS) и unix://. Используется только для RedisCache.

Описание встроенных типов кэша.

NullCache:

Встроенный объект NullCache представляет собой кэш, который отключает кэширование и в основном используется при отладке приложения.

SimpleCache:

Встроенный объект SimpleCache представляет собой кэш, который использует локальный словарь Python для кэширования. Это не совсем потокобезопасно.

Соответствующие параметры конфигурации:

  • CACHE_DEFAULT_TIMEOUT;
  • CACHE_IGNORE_ERRORS;
  • CACHE_THRESHOLD.

FileSystemCache:

Встроенный объект FileSystemCache представляет собой кэш, который использует файловую систему для хранения кэшированных значений.

Соответствующие параметры конфигурации:

  • CACHE_DEFAULT_TIMEOUT;
  • CACHE_IGNORE_ERRORS;
  • CACHE_DIR;
  • CACHE_THRESHOLD;
  • CACHE_OPTIONS.

В CACHE_OPTIONS есть один допустимый ключ mode (режим разрешений в стиле Linux), значение которого должно быть 3-значным восьмеричным числом.

RedisCache:

Встроенный объект RedisCache представляет собой кэш, который использует Redis для хранения кэшированных значений.

Соответствующие параметры конфигурации:

  • CACHE_DEFAULT_TIMEOUT;
  • CACHE_KEY_PREFIX;
  • CACHE_OPTIONS;
  • CACHE_REDIS_HOST;
  • CACHE_REDIS_PORT;
  • CACHE_REDIS_PASSWORD;
  • CACHE_REDIS_DB;
  • CACHE_REDIS_URL.

RedisSentinelCache:

Соответствующие параметры конфигурации:

  • CACHE_KEY_PREFIX;
  • CACHE_REDIS_SENTINELS;
  • CACHE_REDIS_SENTINEL_MASTER;
  • CACHE_REDIS_PASSWORD;
  • CACHE_REDIS_DB.

RedisClusterCache:

Соответствующие параметры конфигурации:

  • CACHE_KEY_PREFIX;
  • CACHE_REDIS_CLUSTER;
  • CACHE_REDIS_PASSWORD.

MemcachedCache:

Встроенный объект MemcachedCache представляет собой кэш, который использует сервер memcached в качестве серверной части. Поддерживает либо pylibmc, либо memcache, либо библиотеку memcache google app engine.

Соответствующие параметры конфигурации:

  • CACHE_DEFAULT_TIMEOUT;
  • CACHE_KEY_PREFIX;
  • CACHE_MEMCACHED_SERVERS.

Примечание. Кэширование в Flask не передает дополнительные параметры конфигурации в бэкенды memcached. Чтобы добавить дополнительную конфигурацию в эти кэши, необходимо явно задать параметры конфигурации для объекта кэша, после создания его экземпляра.

from flask_caching import Cache
cache = Cache()
cache.init_app(flask_app, {"CACHE_TYPE": "memcached"})

# явно устанавливаем параметры для объекта 
# `_client`, при использовании модуля `pylibmc`:
cache.cache._client.behaviors({"tcp_nodelay": True})

SASLMemcachedCache:

Использует сервер memcached в качестве серверной части. Предназначен для использования подключения к серверу memcached с поддержкой SASL. Требуется pylibmc и SASL должен поддерживаться libmemcached.

Соответствующие значения конфигурации

  • CACHE_DEFAULT_TIMEOUT;
  • CACHE_KEY_PREFIX;
  • CACHE_OPTIONS;
  • CACHE_MEMCACHED_SERVERS;
  • CACHE_MEMCACHED_USERNAME;
  • CACHE_MEMCACHED_PASSWORD.

Примечание. В отличие от MemcachedCache, SASLMemcachedCache можно настроить с помощью CACHE_OPTIONS.