flask-cache 缓存Jinja2模板之源码解读

来源:互联网 发布:五星宏辉软件 编辑:程序博客网 时间:2024/05/16 19:23

注:缓存jinja2模板的代码详见:flask-cache缓存的示例代码

1.缓存模板的关键代码:

模板cached_blueprint_app/templates/zen.html
定义缓存参数:

{% cache timeout %}   #timeout是缓存超期时间{% endcache %}        # 缓存区域结束标记

文件cached_blueprint_app/app.py中实例一个当前应用的缓存:

app.cache = Cache(app)

2.源码解读

2.1 Cache类初始化的关键代码如下:

class Cache:    def  __init__(self,app=None,with_jinja2_ext=True,config=None):        if app is not None:            self.init_app(app, config)                                       #<1>     def init_app(self, app, config=None):        if self.with_jinja2_ext:            from .jinja2ext import CacheExtension, JINJA_CACHE_ATTR_NAME     #<2>        setattr(app.jinja_env, JINJA_CACHE_ATTR_NAME, self)                  #<3>               app.jinja_env.add_extension(CacheExtension)                          #<4>     def add_extension(self, extension):                                      #<5>         self.extensions.update(load_extensions(self, [extension]))           #<6>    

上边的代码说明:
<1>初始化当前app缓存操作.
<2>CacheExtension jinja2模板的缓存扩展,实现模板变量缓存的核心功能.
<3>将cache实例存储到jinja_env属性中,方便后边存储缓存时,从环境中取出cache对象.
<4>将CacheExtension加入到jinja环境的扩展中.
<5>当环境创建之后,加入扩展
<6>使用load_extensions的返回结果,来更新扩展程序的字典,实现注册缓存实例到特定环境的功能

2.2 load_extension函数实现CacheExtension的实例化

def load_extensions(environment, extensions):           #<7>    result[extension.identifier]=extension(environment) #<8>

<7>实现从扩展列表中加载扩展,并与当前的环境绑定,返回app环境的实例(一个字典形式)
<8>result 是返回值,是以扩展的标识符为key,以扩展实例为value的字典形式
<8> 扩展标识符是扩展在注册时生成的(ExtensionRegistry类__new__方法实现)

2.3 缓存核心类CacheExtension鸟瞰

UML图如下:
这里写图片描述

说明:
1) CacheExtension的父类Extension实现扩展的基本接口的定义。
2) Extension的父类ExtensionRegistry 实现扩展注册分配标识符的功能。

CacheExtension的功能很简单简单主要有一个字段和两个方法组成:
(1) 字段tags=set([‘cache’])
用于解析匹配,当检测到模板中的tag与CacheExtension的tag字段匹配时,表示当前模板文件有变量需要缓存。
(2) 方法CacheExtension._cache
进行实际的解析操作。当检测到实际的缓存结束的关键字endcache时,会获取整个模板文件的主要内容(body),随后调用内部方法_cache将变量存入缓存中。

    def _cache(self, timeout, fragment_name, vary_on,  caller):        try:            cache = getattr(self.environment, JINJA_CACHE_ATTR_NAME)         #<9>        except AttributeError as e:            raise e        key = make_template_fragment_key(fragment_name, vary_on=vary_on)    #<10>        rv = cache.get(key)        if rv is None:            rv = caller()            cache.set(key, rv, timeout)                                     #<11>        return rvdef make_template_fragment_key(fragment_name, vary_on=[]): """ Make a cache key for a specific fragment name """ if vary_on:     fragment_name = "%s_" % fragment_name return TEMPLATE_FRAGMENT_KEY_TEMPLATE % (fragment_name, "_".join(vary_on))    #<10>

<9> 从jinja环境中取出cache对象
<10> 生成模板的键,键的格式是前缀+完整路径名的形式(如果vary_on不存在)
<11> 将模板中的值存入缓存

附注一个示例的body内容:

Body = [Output(nodes=[TemplateData(data='\n<h3> Random Zen of Python </h3>\n<strong>'),Call(node=Name(name='get_random_quote', ctx='load'), args=[], TemplateData(data='</strong>\n')])]

解释一下:
TemplateData里边模板的具体内容。
Call里边是模板调用的方法get_random_quote
ExtensionRegistry 类的代码很简单,只有一个创建对象的方法。实现了两个功能:
1创建类2.为类创建唯一的表示符

class ExtensionRegistry(type):    """Gives the extension an unique identifier."""    def __new__(cls, name, bases, d):        rv = type.__new__(cls, name, bases, d)        rv.identifier = rv.__module__ + '.' + rv.__name__   #标识符采用包名+'.'+类名        return rv

在对jinja缓存时,CacheExtension的扩展标识符(identifier)是:flask_cache.jinja2ext.CacheExtension。这样可以区分不同包下相同类的标识符唯一的情况。

3.缓存模板的完整函数调用图:

这里写图片描述

原创粉丝点击