Flask缓存技术(Flask-Cache)
为了给用户良好体验,为了节省堆统一资源多次调用所带来的资源浪费,缓存成为了Web服务器比较重要的概念。在Django中也有很多不同类别的缓存以及缓存的范围。利用内置的缓存模块,我们可以对某一页面,某一模板,某些数据进行缓存。在Flask中,也同样可以,但要使用扩展模块Flask-Cache。
基本使用方法:
app = Flask( name )
cache = Cache(app)
@app.route('/hello')
@cache.cached(timeout=300, key_prefix='view_%s', unless=None)
def hello(name=None):
return render_template('hello.html', name=name)
cache = Cache(app),创建缓存实例化时,cache类会自动从app配置文件中获得缓存类型,缓存时间等信息,源代码如下:
class Cache(object):
""" This class is used to control the cache objects. """
def __init__(self, app=None, with_jinja2_ext=True, config=None):
if not (config is None or isinstance(config, dict)):
raise ValueError("`config` must be an instance of dict or None")
self.with_jinja2_ext = with_jinja2_ext
self.config = config
self.app = app
if app is not None:
self.init_app(app, config)
def init_app(self, app, config=None):
"This is used to initialize cache with your app object"
base_config = app.config.copy()
if self.config:
base_config.update(self.config)
if config:
base_config.update(config)
config = base_config
config.setdefault('CACHE_DEFAULT_TIMEOUT', 300)
config.setdefault('CACHE_THRESHOLD', 500)
config.setdefault('CACHE_KEY_PREFIX', 'flask_cache_')
config.setdefault('CACHE_MEMCACHED_SERVERS', None)
config.setdefault('CACHE_DIR', None)
config.setdefault('CACHE_OPTIONS', None)
config.setdefault('CACHE_ARGS', [])
config.setdefault('CACHE_TYPE', 'null')
config.setdefault('CACHE_NO_NULL_WARNING', False)
if self.with_jinja2_ext:
from .jinja2ext import CacheExtension, JINJA_CACHE_ATTR_NAME
setattr(app.jinja_env, JINJA_CACHE_ATTR_NAME, self)
app.jinja_env.add_extension(CacheExtension)
self._set_cache(app, config)
从上面代码中就可以看出,init_app方法浅拷贝了app的config对象。配置之后会设定cache对象。cache对象默认为simple,使用本地Python字典缓存。这不是真正的线程安全。,此外还有RedisCache,SASLMemcachedCache等等。
这里最关键的是缓存的cached方法,该方法是一个装饰器,经过该装饰器修饰的视图函数,会自动将视图函数返回值存储到指定的缓存值,存储形式是key-value.
cached方法原型:
def cached(self, timeout=None, key_prefix='view/%s', unless=None):
"""
Decorator. Use this to cache a function. By default the cache key
is `view/request.path`. You are able to use this decorator with any
function by changing the `key_prefix`. If the token `%s` is located
within the `key_prefix` then it will replace that with `request.path`
:param timeout: Default None. If set to an integer, will cache for that
amount of time. Unit of time is in seconds.
:param key_prefix: Default 'view/%(request.path)s'. Beginning key to .
use for the cache key.
:param unless: Default None. Cache will *always* execute the caching
facilities unless this callable is true.
This will bypass the caching entirely.
"""
def decorator(f):
@functools.wraps(f)
def decorated_function(*args, **kwargs):
try:
cache_key = decorated_function.make_cache_key(*args, **kwargs)
rv = self.cache.get(cache_key)
except Exception:
if current_app.debug:
raise
logger.exception("Exception possibly due to cache backend.")
return f(*args, **kwargs)
if rv is None:
rv = f(*args, **kwargs)
try:
self.cache.set(cache_key, rv,
timeout=decorated_function.cache_timeout)
except Exception:
if current_app.debug:
raise
logger.exception("Exception possibly due to cache backend.")
return f(*args, **kwargs)
return rv
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
decorated_function.uncached = f
decorated_function.cache_timeout = timeout
decorated_function.make_cache_key = make_cache_key
return decorated_function
return decorator
上述代码还是比较好理解,首先根据cache_key(默认是request.path,即当前路由)取值,如果存在,即直接返回value值,如果没有,那么就执行该函数,并把函数返回值存到缓存中。
上面是一个三层装饰器,一般装饰器本身需要带参数的都采用三层。
我真是觉得上面的缓存装饰器写得特别好,我后来在Django项目中就根据这个写了一个缓存装饰器。
--------EOF---------
微信分享/微信扫码阅读
微信分享/微信扫码阅读