Flask-Cache坑之无法缓存带参数的网址

Flask-cache 模块

flask-cache 安装

pip install flask-cache

flask-cache 使用

入口文件:

"""
app.py
"""
from myapp import create_app
app = create_app()
if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0", port=8080)

工厂函数文件:


from flask import Flask
from myapp.config import Config  # 自定义的config类
"""
myapp/__init__.py
"""

def create_app():    
    """工厂函数"""
    app = Flask(__name__)    
    app.config.from_object(Config)

    from myapp.extension import cache
    cache.init_app(app)  #  cache 实例配置化


    from myapp.main import main
    app.register_blueprint(main, url_prefix="/")
    return app

Config配置文件

"""
myapp/config.py
"""
class Config:
    """
    在这里使用redis作为缓存,如果使用 系统内存作为缓存则CACHE_TYPE = 'simple'即可
    """
    SECRET_KEY = '1@3$23^7*9)'
    CACHE_TYPE = 'redis'
    CACHE_REDIS_HOST = '127.0.0.1'
    CACHE_REDIS_PORT = 6379
    CACHE_REDIS_DB = 1



自定义扩展文件:

"""
myapp/extension.py
"""

from flask_cache import Cache

cache = Cache(with_jinja2_ext=False)
# with_jinja2_ext是指是否在jinja模版中开启cache的应用
# 这里由于jinja模版中用了import flask.ext.cache 这种过时的代码,因此with_jinja2_ext=True时会报错

视图文件:
在这里使用 缓存,需要在哪个视图

"""
myapp/main/__init__.py
"""
from flask import Blueprint
from myapp.extension import cache

main = Blueprint('main', __name__)

@main.route("/", methods=["GET", "POST"])
@cache.cached()
def index():    
    print("第一次访问可以在控制台看到我")    
    return "hello world"


@main.route("/hello", methods=["GET", "POST"])
def hello():    
    print("每一次访问可以在控制台看到我")    
    return "hello world"

然后在cmd或者shell转移到项目根目录,运行命令即可启动项目

python app.py

可以看到,先实例化Cache,再将cache.cached()作为试图函数的装饰器即可

flask-cache 无法正确缓存带提交参数的url

使用的过程发现有一些url没办法被正确缓存
贴视图函数文件:

"""
myapp/main/__init__.py
"""
from flask import Blueprint, request
from myapp.extension import cache

main = Blueprint('main', __name__)

@main.route("/", methods=["GET", "POST"])
@cache.cached()
def index():    
    name = request.args.get("name", "Su San")
    print("第一次访问可以在控制台看到我")    
    return "hello world :"+name


@main.route("/hello", methods=["GET", "POST"])
def hello():    
    print("每一次访问可以在控制台看到我")    
    return "hello world"

这是怎么回事呢?

查看 cache.cached()的源码,发现关于缓存的键生成部分的源码:

class Cache(object):   
"""    This class is used to control the cache objects.    """

    ...
    
    def cached(self, timeout=None, key_prefix='view/%s', unless=None):
        ...
        
        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

make_cache_key()这个函数生成储存缓存对应的字符串键,
可以看,按默认配置的话
cache_key = key_prefix % request.path

其中request.path 是指 请求的网址的地址部分
在例子
http://127.0.0.1:8080/?name=橘子快乐
中对应 http://127.0.0.1:8080与?中间的部分 即/

因此无论是
http://127.0.0.1:8080/?name=橘子郁闷
还是http://127.0.0.1:8080/?name=橘子快乐,其缓存键值都是"/",相当于缓存了同个内容

将参数加入缓存键值的方法

查看make_cache_key()中第一个if,表明我们可以将自定义键值函数传进去,这是一个方法。
查request变量内容

以下表格内容摘自 【Flask】关于Flask的request属性-阏男秀
如果用户请求如下URL: http://www.example.com/myapplication/page.html?x=y 以上的参数内容如下:

名称内容
path/page.html
script_root/myapplication
base_urlhttp://www.example.com/myapplication/page.html
urlhttp://www.example.com/myapplication/page.html?x=y
url_roothttp://www.example.com/myapplication/

可以看到,我们需要的是request.url,里面带有参数

重写视图文件:

"""
myapp/main/__init__.py
"""
from flask import Blueprint, request, current_app
from myapp.extension import cache

main = Blueprint('main', __name__)

def key_prefix_func():    
    key_prefix = "view%s"
    with current_app.app_context():       
        if '%s' in key_prefix:            
            # 这里改成request.url
            cache_key = key_prefix % request.url        
        else:            
            cache_key = key_prefix
    return cache_key



@main.route("/", methods=["GET", "POST"])
@cache.cached(key_prefix=key_prefix_func)
def index():    
    name = request.args.get("name", "Su San")
    print("第一次访问可以在控制台看到我")    
    return "hello world :"+name


@main.route("/hello", methods=["GET", "POST"])
def hello():    
    print("每一次访问可以在控制台看到我")    
    return "hello world"

添加缓存变成@cache.cached(key_prefix=key_prefix_func)
但这样 并不方便,每个地方都得添加key_prefix=key_prefix_func的参数

因此需要对cache进行简单封装以下,重写extension.py

"""
myapp/extension.py
"""

from flask_cache import Cache
from flask import request, current_app

cache = Cache(with_jinja2_ext=False)
# with_jinja2_ext是指是否在jinja模版中开启cache的应用
# 这里由于jinja模版中用了import flask.ext.cache 这种过时的代码,因此with_jinja2_ext=True时会报错

def cache_with_param(timeout=None, key_prefix='view/%s', unless=None):
    """
    直接封装 cache.cached,使用起来更简单
    """
    def key_prefix_func():
        with current_app.app_context():
            if '%s' in key_prefix:
                cache_key = key_prefix % request.url
            else: 
                cache_key = key_prefix
        return cache_key
    return cache.cached(timeout=timeout, key_prefix=key_prefix_func, unless=unless)

使用的试图函数:

"""
myapp/main/__init__.py
"""
from flask import Blueprint, request, current_app
from myapp.extension import cache_with_param

main = Blueprint('main', __name__)


# 使用cache_with_param() 代替 cache.cached()
@main.route("/", methods=["GET", "POST"])
@cache_with_param()
def index():    
    name = request.args.get("name", "Su San")
    print("第一次访问可以在控制台看到我")    
    return "hello world :"+name


@main.route("/hello", methods=["GET", "POST"])
def hello():    
    print("每一次访问可以在控制台看到我")    
    return "hello world"
  • 注意,这里只让缓存注意到了网址中的参数,即GET的参数,关于POST的参数只需要修改代码中关于request.url的部分,可以使用str(dict(request.values.items())) 简单代替,但一般不会有人缓存POST的请求内容吧
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值