Flask-Caching

Flask-Caching 是 Flask 的一个扩展,为任何 Flask 应用程序添加了对各种后端的缓存支持。它基于 cachelib 运行,因此通过统一的 API 支持 werkzeug 的所有原始缓存后端。也可以通过继承 flask_caching.backends.base.BaseCache 类来开发您自己的缓存后端。

版本支持

从 1.8 版本开始,Flask-Caching 仅支持 Python 3.5+。

安装

使用以下命令安装扩展

$ pip install Flask-Caching

设置

缓存通过 Cache 实例管理

from flask import Flask
from flask_caching import Cache

config = {
    "DEBUG": True,          # some Flask specific configs
    "CACHE_TYPE": "SimpleCache",  # Flask-Caching related configs
    "CACHE_DEFAULT_TIMEOUT": 300
}
app = Flask(__name__)
# tell Flask to use the above defined config
app.config.from_mapping(config)
cache = Cache(app)

您也可以稍后在配置时使用 init_app 方法设置您的 Cache 实例

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

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

您还可以提供一个备用配置字典,如果存在多个 Cache 实例,每个实例具有不同的后端,这将非常有用

#: Method A: During instantiation of class
cache = Cache(config={'CACHE_TYPE': 'SimpleCache'})
#: Method B: During init_app call
cache.init_app(app, config={'CACHE_TYPE': 'SimpleCache'})

0.7 版本新增。

缓存视图函数

要缓存视图函数,您将使用 cached() 装饰器。默认情况下,此装饰器将使用 request.path 作为 cache_key

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

cached 装饰器还有另一个可选参数,名为 unless。此参数接受一个可调用对象,该对象返回 True 或 False。如果 unless 返回 True,则它将完全绕过缓存机制。

要在视图中动态确定超时时间,您可以返回 CachedResponse,它是 flask.Response 的子类

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

警告

在视图上使用 cached 时,请注意将其放在 Flask 的 @route 装饰器和您的函数定义之间。例如

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

如果您反转这两个装饰器,缓存的将是 @route 装饰器的结果,而不是您的视图函数的结果。

缓存可插拔视图类

Flask 的可插拔视图类也受支持。要缓存它们,请在 dispatch_request 方法上使用相同的 cached() 装饰器

from flask.views import View

class MyView(View):
    @cache.cached(timeout=50)
    def dispatch_request(self):
        return 'Cached for 50s'

缓存其他函数

使用相同的 @cached 装饰器,您可以缓存其他非视图相关函数的结果。唯一的规定是您需要替换 key_prefix,否则它将使用 request.path 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()

制作自定义 缓存键

有时您想为每个路由定义您的缓存键。使用相同的 @cached 装饰器,您可以指定如何生成此键。当缓存的键不应仅仅是默认的 key_prefix,而必须从请求中的其他参数派生时,这可能很有用。一个示例用例是缓存 POST 路由。其中缓存键应从该请求中的数据派生,而不仅仅是路由/视图本身。

make_cache_key 可用于指定这样的函数。该函数应返回一个字符串,该字符串应充当缓存所需值的键

def make_key():
   """A function which is called to derive the key for a computed value.
      The key in this case is the concat value of all the json request
      parameters. Other strategy could to use any hashing function.
   :returns: unique string for which the value should be cached.
   """
   user_data = request.get_json()
   return ",".join([f"{key}={value}" for key, value in user_data.items()])

@app.route("/hello", methods=["POST"])
@cache.cached(timeout=60, make_cache_key=make_key)
def some_func():
   ....

记忆化

请参阅 memoize()

在记忆化中,函数参数也包含在 cache_key 中。

注意

对于不接收参数的函数,cached()memoize() 实际上是相同的。

Memoize 也为方法设计,因为它将考虑 identity。作为缓存键一部分的 'self' 或 'cls' 参数的标识。

记忆化背后的理论是,如果您有一个函数需要在单个请求中多次调用,则该函数仅在第一次使用这些参数调用时才会被计算。例如,一个 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

警告

使用可变对象(类等)作为缓存键的一部分可能会变得棘手。建议不要将对象实例传递到记忆化函数中。但是,memoize 会对传入的参数执行 repr(),因此如果对象具有 __repr__ 函数,该函数返回该对象的唯一标识字符串,则该字符串将用作缓存键的一部分。

例如,一个 sqlalchemy person 对象,它返回数据库 ID 作为唯一标识符的一部分

class Person(db.Model):
    def __repr__(self):
        return "%s(%s)" % (self.__class__.__name__, self.id)

删除记忆化缓存

0.2 版本新增。

您可能需要按函数删除缓存。使用上面的示例,假设您更改了用户的权限并将他们分配给一个角色,但是现在您需要重新计算他们是否具有某些成员资格。您可以使用 delete_memoized() 函数来执行此操作

cache.delete_memoized(user_has_membership)

注意

如果仅将函数名称作为参数给出,则将使该函数的所有记忆化版本都无效。但是,您可以通过提供与缓存时相同的参数值来删除特定缓存。在以下示例中,仅删除 user-role 缓存

user_has_membership('demo', 'admin')
user_has_membership('demo', 'user')

cache.delete_memoized(user_has_membership, 'demo', 'user')

警告

如果类方法被记忆化,则必须提供 class 作为第一个 *args 参数。

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 代码片段

用法

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

默认情况下,“模板文件路径”+“块起始行”的值用作缓存键。此外,可以手动设置键名。键被连接在一起成为一个字符串,该字符串可用于避免在不同模板中评估相同的块。

将超时设置为 None 以实现无超时,但使用自定义键

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

将超时设置为 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)

考虑到我们有 render_form_fieldrender_submit

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

清除缓存

请参阅 clear()

这是一个清空应用程序缓存的示例脚本

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())来显式缓存数据。Cache 类提供了许多其他代理方法。

例如

@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

Flask-Caching 存在以下配置值

CACHE_TYPE

指定要使用的缓存对象类型。这是一个导入字符串,将被导入和实例化。假定导入的对象是一个函数,该函数将返回一个符合缓存 API 的缓存对象。

对于 flask_caching.backends.cache 对象,您不需要指定整个导入字符串,只需指定以下名称之一。

内置缓存类型

  • NullCache (默认;旧名称为 null)

  • SimpleCache (旧名称为 simple)

  • FileSystemCache (旧名称为 filesystem)

  • RedisCache (需要 redis;旧名称为 redis)

  • RedisSentinelCache (需要 redis;旧名称为 redissentinel)

  • RedisClusterCache (需要 redis;旧名称为 rediscluster)

  • UWSGICache (需要 uwsgi;旧名称为 uwsgi)

  • MemcachedCache (需要 pylibmc 或 memcache;旧名称为 memcachedgaememcached)

  • SASLMemcachedCache (需要 pylibmc;旧名称为 saslmemcached)

  • SpreadSASLMemcachedCache (需要 pylibmc;旧名称为 spreadsaslmemcached)

CACHE_NO_NULL_WARNING

在使用 'null' 缓存类型时,静默警告消息。

CACHE_ARGS

可选列表,在缓存类实例化期间解包并传递。

CACHE_OPTIONS

在缓存类实例化期间传递的可选字典。

CACHE_DEFAULT_TIMEOUT

如果未指定其他超时,则使用的超时。时间单位为秒。默认为 300

CACHE_IGNORE_ERRORS

如果设置为 True,则删除过程中发生的任何错误都将被忽略。但是,如果设置为 False,则会在第一个错误时停止。此选项仅与 filesystemsimple 后端相关。默认为 False

CACHE_THRESHOLD

缓存将存储的最大项目数,超过此数目后,它将开始删除一些项目。仅用于 SimpleCache 和 FileSystemCache。默认为 500

CACHE_KEY_PREFIX

添加到所有键之前的前缀。这使得可以将同一 memcached 服务器用于不同的应用程序。仅用于 RedisCache 和 MemcachedCache。默认为 flask_cache_

CACHE_SOURCE_CHECK

应用于函数装饰器的默认条件,用于控制在形成用作缓存键的哈希时是否应包含函数的源代码。这确保了如果源代码更改,即使参数相同,调用新函数时也不会返回缓存的值。默认为 False

CACHE_UWSGI_NAME

要连接的 uwsgi 缓存实例的名称,例如:mycache@localhost:3031,默认为空字符串,这意味着 uWSGI 将在本地实例中缓存。如果缓存与 werkzeug 应用程序在同一实例中,您只需提供缓存的名称。

CACHE_MEMCACHED_SERVERS

服务器地址的列表或元组。仅用于 MemcachedCache

CACHE_MEMCACHED_USERNAME

用于 memcached 的 SASL 身份验证的用户名。仅用于 SASLMemcachedCache

CACHE_MEMCACHED_PASSWORD

用于 memcached 的 SASL 身份验证的密码。仅用于 SASLMemcachedCache

CACHE_REDIS_HOST

Redis 服务器主机。仅用于 RedisCache。

CACHE_REDIS_PORT

Redis 服务器端口。默认为 6379。仅用于 RedisCache。

CACHE_REDIS_PASSWORD

服务器的 Redis 密码。仅用于 RedisCache 和 RedisSentinelCache。

CACHE_REDIS_DB

Redis db(从零开始的数字索引)。默认为 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

连接到 Redis 服务器的 URL。示例 redis://user:password@localhost:6379/2。支持协议 redis://rediss:// (redis over TLS) 和 unix://。有关 URL 支持的更多信息,请参阅 [此处](https://redis-py.pythonlang.cn/en/latest/index.html#redis.ConnectionPool.from_url)。仅用于 RedisCache。

内置缓存后端

NullCache

CACHE_TYPE 设置为 NullCache 以使用此类型。旧名称 null 已弃用,将在 Flask-Caching 2.0 中删除。

不缓存的缓存

  • CACHE_DEFAULT_TIMEOUT

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

SimpleCache

CACHE_TYPE 设置为 SimpleCache 以使用此类型。旧名称 simple 已弃用,将在 Flask-Caching 2.0 中删除。

使用本地 python 字典进行缓存。这实际上不是线程安全的。

相关配置值

  • CACHE_DEFAULT_TIMEOUT

  • CACHE_IGNORE_ERRORS

  • CACHE_THRESHOLD

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

FileSystemCache

CACHE_TYPE 设置为 FileSystemCache 以使用此类型。旧名称 filesystem 已弃用,将在 Flask-Caching 2.0 中删除。

使用文件系统存储缓存值

  • CACHE_DEFAULT_TIMEOUT

  • CACHE_IGNORE_ERRORS

  • CACHE_DIR

  • CACHE_THRESHOLD

  • CACHE_OPTIONS

CACHE_OPTIONS 中有一个有效的条目:mode,它应该是 3 位 linux 风格的权限八进制模式。

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

RedisCache

CACHE_TYPE 设置为 RedisCache 以使用此类型。旧名称 redis 已弃用,将在 Flask-Caching 2.0 中删除。

  • CACHE_DEFAULT_TIMEOUT

  • CACHE_KEY_PREFIX

  • CACHE_OPTIONS

  • CACHE_REDIS_HOST

  • CACHE_REDIS_PORT

  • CACHE_REDIS_PASSWORD

  • CACHE_REDIS_DB

  • CACHE_REDIS_URL

CACHE_OPTIONS 中的条目作为 **kwargs 传递给 redis 客户端

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

RedisSentinelCache

CACHE_TYPE 设置为 RedisSentinel 以使用此类型。旧名称 redissentinel 已弃用,将在 Flask-Caching 2.0 中删除。

  • CACHE_KEY_PREFIX

  • CACHE_REDIS_SENTINELS

  • CACHE_REDIS_SENTINEL_MASTER

  • CACHE_REDIS_PASSWORD

  • CACHE_REDIS_DB

CACHE_OPTIONS 中的条目作为 **kwargs 传递给 redis 客户端

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

RedisClusterCache

CACHE_TYPE 设置为 RedisClusterCache 以使用此类型。旧名称 rediscluster 已弃用,将在 Flask-Caching 2.0 中删除。

  • CACHE_KEY_PREFIX

  • CACHE_REDIS_CLUSTER

  • CACHE_REDIS_PASSWORD

CACHE_OPTIONS 中的条目作为 **kwargs 传递给 redis 客户端

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

MemcachedCache

CACHE_TYPE 设置为 MemcachedCache 以使用此类型。旧名称 memcachedgaememcached 已弃用,将在 Flask-Caching 2.0 中删除。

使用 memcached 服务器作为后端。支持 pylibmc 或 memcache 或 google app engine memcache 库。

相关配置值

  • CACHE_DEFAULT_TIMEOUT

  • CACHE_KEY_PREFIX

  • CACHE_MEMCACHED_SERVERS

注意

Flask-Caching 不会将其他配置选项传递给 memcached 后端。要向这些缓存添加其他配置,请在实例化后直接在对象上设置配置选项

from flask_caching import Cache
cache = Cache()

# Can't configure the client yet...
cache.init_app(flask_app, {"CACHE_TYPE": "memcached"})

# Break convention and set options on the _client object
# directly. For pylibmc behaviors:
cache.cache._client.behaviors({"tcp_nodelay": True})

或者,请参阅 自定义缓存后端

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

SASLMemcachedCache

CACHE_TYPE 设置为 SASLMemcachedCache 以使用此类型。旧名称 saslmemcached 已弃用,将在 Flask-Caching 2.0 中删除。

使用 memcached 服务器作为后端。旨在与启用 SASL 的 memcached 服务器连接一起使用。需要 pylibmc,并且 libmemcached 必须支持 SASL。

相关配置值

  • CACHE_DEFAULT_TIMEOUT

  • CACHE_KEY_PREFIX

  • CACHE_OPTIONS

  • CACHE_MEMCACHED_SERVERS

  • CACHE_MEMCACHED_USERNAME

  • CACHE_MEMCACHED_PASSWORD

注意

与 MemcachedCache 不同,SASLMemcachedCache 可以使用 CACHE_OPTIONS 进行配置。

0.10 版本新增。

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

SpreadSASLMemcachedCache

CACHE_TYPE 设置为 SpreadSASLMemcachedCache 以使用此类型。旧名称 spreadsaslmemcached 已弃用,将在 Flask-Caching 2.0 中删除。

与 SASLMemcachedCache 相同,但是,如果值大于 memcached 阈值(默认为 1M),它能够将值分散到多个键中。使用 pickle。

0.11 版本新增。

在 1.1.0 版本中更改: 为了保持一致性,将 spreadsaslmemcachedcache 重命名为 spreadsaslmemcached

在 1.9.1 版本中更改: 弃用旧名称,赞成仅使用类名。

UWSGICache

警告

UWSGICache 未维护也未测试。使用风险自负。

CACHE_TYPE 设置为 flask_caching.contrib.uwsgicache.UWSGICache 以使用此类型。您还必须将 CACHE_UWSGI_NAME 设置为您在 uWSGI 配置中设置的缓存名称。

自定义缓存后端

您可以通过公开一个可以实例化并返回缓存对象的函数来轻松添加自己的自定义缓存后端。CACHE_TYPE 将是您自定义缓存类型的导入字符串。如果不是 flask_caching.backends.cache.BaseCache 的子类,Flask-Caching 将使用三个参数调用它

  • app,为其初始化缓存的 Flask 应用程序对象

  • args,CACHE_ARGS 配置选项的值

  • kwargs,CACHE_OPTIONS 配置选项的值

注意

argskwargs 在实例化缓存对象时不会展开,即,它们不会作为 *args**kwargs 传入,但它们是 CACHE_ARGS 和 CACHE_OPTIONS 配置选项的精确值(但是,CACHE_ARGS 会转换为列表)。

但是,您的自定义缓存应子类化 flask_caching.backends.cache.BaseCache 类,以便它提供所有必要的方法以供使用。

在 1.9.1 版本中更改: 如果您的自定义缓存类型 flask_caching.backends.cache.BaseCache 的子类,则 Flask-Caching 将调用其 factory 类方法,而不是直接实例化该类,并使用上面列出的相同参数。除非被覆盖,否则 BaseCache.factory 只是实例化对象,而无需向其传递任何参数。内置缓存类已覆盖此方法以模仿旧的、基于函数的缓存实例化,因此如果您子类化了不是 flask_caching.backends.cache.BaseCache 的内容,您可能需要查阅源代码以查看您的类是否仍然兼容。

一个示例实现

#: the_app/custom.py
class RedisCache(BaseCache):
    def __init__(self, servers, default_timeout=500):
        pass

    @classmethod
    def factory(cls, app, args, kwargs):
        args.append(app.config['REDIS_SERVERS'])

        return cls(*args, **kwargs)

在此示例中,您的 CACHE_TYPE 可能是 the_app.custom.RedisCache

CACHE_TYPE 不必直接指向缓存类。一个示例 PylibMC 缓存实现,用于更改二进制设置并在库上启用 SASL 时提供用户名/密码

#: the_app/custom.py
def pylibmccache(app, config, args, kwargs):
    return pylibmc.Client(servers=config['CACHE_MEMCACHED_SERVERS'],
                          username=config['CACHE_MEMCACHED_USERNAME'],
                          password=config['CACHE_MEMCACHED_PASSWORD'],
                          binary=True)

在此示例中,您的 CACHE_TYPE 可能是 the_app.custom.pylibmccache

API

附加信息