flask-cache 默认将 (view/%s) % request.path 作为cache_key,但有时并不能满足实际需要,例如当url中有参数,且参数也要作为cache_key的一部分时,那么不同的参数就会共用一个缓存,这显然是错的。
例如有一个路由 /item
, /item?page=0 表示第一页的数据, /item?page=1 表示第二页的数据。我们想把这两个url生成两个不同的cache_key,按照默认生成cache_key的方式只会生成同一个, 那就是view//item。我们可能会尝试增加key_prefix参数,但是我们怎么拿到page参数呢,因为获取url参数不能脱离request上下文环境,所以在装饰器中是拿不到的。
我们只能重写默认的cache_key生成机制,源码中是这样的:
def make_cache_key(*args, **kwargs):
if callable(key_prefix):
cache_key = key_prefix()
elif '%s' in key_prefix:
cache_key = key_prefix % request.path
else:
cache_key = key_prefix
return cache_key
我们可以根据需要改变这个方式,在这里我们只需要把request.path 改成 request.url 即可。但是
, 怎么改呢? 直接去改源码吗?这涉及到python中修改第三方库的方式,主要有三种方式,第一种是将源码fork下来修改后自己发布,第二种是用类继承的方式,第三种是monkey patch (猴子补丁)的方式。猴子补丁 第三方库修改方式
这里我用的是第三种(勉强算吧,我也才开始接触) 。首先,把cached方法copy到一个单独的模块中,然后根据需要修改。然后将修改后的方法添加到cache实例中以覆盖之前的方法。例如:
from app.utils.cache import cached, delete_like
from flask_cache import Cache
cache = Cache(config={'CACHE_TYPE': 'simple'})
cache.init_app(app) # 注册缓存
# 重写缓存key_prefix机制
cache.cached = cached
注意
,因为我们重写的是实例方法,实例方法的第一个参数是self,所以我们在调用这个方法时要将cache实例本身也作为参数传进去。例如:
@cache.cached(cache, timeout=300, key_prefix='get_item_%s')
[完]