Django 缓存框架

171 阅读6分钟

每次用户请求页面时,web服务器都会进行各种计算,以创建网站访问者看到的页面。缓存的目的就是保留这些计算结果,以免多次进行重复的计算。


设置缓存

缓存系统需要少量的设置。也就是说,你必须告诉它你的缓存数据应该放在哪里 —— 是在数据库中,还是在文件系统上,或者直接放在内存中。这是一个重要的决定,会影响你的缓存的性能;是的,有些缓存类型比其他类型快。

缓存设置项位于你的配置文件的缓存配置中。这里有缓存配置所有可用值的说明。


访问缓存

  • django.core.cache.caches

你可以通过类似字典一样的对象访问在CACHES配置的缓存,重复请求同一个线程里的同一个别名将返回同一个对象。

>>> from django.core.cache import caches
>>> cache1 = caches['myalias']
>>> cache2 = caches['myalias']
>>> cache1 is cache2
True

如果键名不存在,将会引发 InvalidCacheBackendError 错误。

  • django.core.cache.cache

django.core.cach.cachedafault缓存的快捷方式。

from django.core.cache import cache

这个对象等价于caches['default']

设置redis缓存

首先,您需要在本地或远程机器上运行Redis服务器。要使用Redis作为Django的缓存后端,需要

  • BACKEND设置为django.core.cache.backends.redis.RedisCache
  • LOCATION设置为指向Redis实例的URL

例如,当Redis在本地运行,使用端口6379时:

CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
    }
}

如果Redis被验证系统保护,那需要将username和password添加进LOCATION的URL中:

CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.redis.RedisCache",
        "LOCATION": "redis://username:password@127.0.0.1:6379",
    }
}

Caches 参数说明

  • BACKEND:要使用的缓存后端。内置的缓存后端有
'django.core.cache.backends.db.DatabaseCache' # 数据库缓存
'django.core.cache.backends.dummy.DummyCache' # 开发调试缓存
'django.core.cache.backends.filebased.FileBasedCache' # 文件缓存
'django.core.cache.backends.locmem.LocMemCache' # 内存缓存
'django.core.cache.backends.memcached.PyMemcacheCache' # Memcache缓存(python-memcached模块)
'django.core.cache.backends.memcached.PyLibMCCache' # Memcache缓存(pylibmc模块)
'django.core.cache.backends.redis.RedisCache' # Redis缓存
  • LOCATION:要使用的高速缓存的位置。可能是文件系统缓存的目录,memcache 服务器的主机和端口,或者是本地内存缓存的识别名称,例如
CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.filebased.FileBasedCache",# 文件缓存
        "LOCATION": "/var/tmp/django_cache",
    }
}
  • OPTIONS:传递给缓存后端的额外参数。可用的参数根据你的缓存后端不同而不同。
  • TIMEOUT:缓存的默认超时时间,以秒为单位。这个参数默认为 300 秒(5 分钟)。你可以将 TIMEOUT 设置为 None,这样,默认情况下,缓存键永远不会过期。值为 0 会导致键立即过期(实际上是 “不缓存”)。

基本用法

  • cache.set(key, value, timeout=DEFAULT_TIMEOUT, version=None)
  • cache.get(key, default=None, version=None)

key 是一个字符串,value 可以任何 picklable 形式的 Python 对象。

timeout 参数是可选的,默认为 CACHES中相应后端的 timeout 参数。它是值存在缓存里的秒数。timeout 设置为 None 时将永久缓存。timeout 为0将不缓存值。

cache.get()可以采用default参数。这指定了在缓存中不存在key时要返回的值。没有设置default,则返回None

>>> cache.set('my_key', 'hello, world!', 30)
>>> cache.get('my_key')
'hello, world!'
>>> time.sleep(30)
>>> cache.get('my_key')
None
>>> cache.get('my_key', 'has_expired')
'has_expired'
  • cache.add(key, value, timeout=DEFAULT_TIMEOUT, version=None)

仅在key不存在的情况下添加,类似set(),但是key存在时,不会更新key对应的缓存。

>>> cache.set("add_key", "Initial value")
>>> cache.add("add_key", "New value")
>>> cache.get("add_key")
'Initial value'

如果set()add()成功将value保存在缓存中,将返回True,否则返回False

>>> print(cache.set('my_key', 'my_value', 30))
True
>>> print(cache.add('my_key', 'new_value', 30))
False
>>> time.sleep(30)
>>> print(cache.add('my_key', 'new_value', 30))
True
  • cache.get_or_set(key, default, timeout=DEFAULT_TIMEOUT, version=None)

得到key对应的值或者在key不存在时缓存值并返回。

>>> cache.get('my_new_key')
None
>>> cache.get_or_set('my_new_key', 'my_new_value', 5)
'my_new_value'
>>> cache.get('my_new_key')
'my_new_value'
  • cache.get_many(keys, version=None)

keys是一个有key组成的列表,返回一个字典,里面只有在缓存中存在的键值对。

>>> cache.set('a', 'A', 10)
>>> cache.set('b', 'B', 10)
>>> cache.set('c', 'C', 10)
>>> cache.set('e', 'E', 10)
>>> cache.get_many(['a', 'b', 'c', 'd', 'e']
OrderedDict([('a', 'A'), ('b', 'B'), ('c', 'C'), ('e', 'E')])
  • cache.set_many(dict, timeout)

更方便地缓存多个值,dict是一个包含多个键值对的字典。

>>> cache.set_many({"a":"A", "b":"B", "c":"C"}, 600)
>>> cache.set_many({"a":"A", "b":"B", "c":"C"}, 600)
>>> cache.get_many(["a", "b", "c", "d"])
OrderedDict([('a', 'A'), ('b', 'B'), ('c', 'C')])
  • cache.delete(key, version=None)

删除某个key在缓存中对应的值,删除成功返回True,删除失败返回False

>>> cache.set("a", "A", 300)
True
>>> cache.get("a")
'A'
>>> cache.delete("a")
True
>>> cache.delete("b")
False
  • cache.delete_many(keys, version=None)

更便捷地删除多个key对应的缓存中的值。返回的是<class 'int'>类型,表示删除成功的value的数量。

  • cache.clear()

最后,如果你想删除缓存中的所有key,可以使用cache.clear()clear()将从缓存中删除所有内容,而不仅仅是应用程序设置的key;返回None

  • cache.touch(key, timeout=DEFAULT_TIMEOUT, version=None)

cache.touch()为密钥设置新的过期时间。例如,将密钥更新为从现在起10秒过期:

>>> cache.touch('a', 10)
True

使用django-redis

django-redis 基于 BSD 许可, 是一个使 Django 支持 Redis cache/session 后端的全功能组件.

安装

pip install django-redis

作为 cache backend 使用配置

为了使用 django-redis , 你应该将你的 django cache 设置改成这样:

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}

如果需要密码,可以写入到OPTIONS内:

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "PASSWORD": "mysecret"
        }
    }
}

作为 session backend 使用配置

Django 默认可以使用任何 cache backend 作为 session backend, 将 django-redis 作为 session 储存后端不用安装任何额外的 backend。

SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "default"

进阶用法

  • cacge.ttl(key)

在redis中, 你可以获取任何key的ttl(Time to live, 过期时间), django-redis也支持获取ttl的函数。

key不存在或已过期,返回0;当设置永久保存时(timeout=None),返回None;其他情况返回当前的过期时间。

>>> cache.set('a', 'A', 60)
>>> cache.ttl('a')
60
>> cache.ttl('b')
0
  • cache.persist(key)
  • cache.expire(key, timeout)

persist()方法可以让key对应的值永久储存在缓存中,而expire()方法可以给key对应的值指定一个新的过期时间。

>>> cache.set('a', 'A', 60)
>>> cache.persist('a')
True
>>> cache.ttl('a')
None
>> cache.expire('a', 60)
True
>> cache.ttl('a)
60
  • cache.keys(str)
  • cache.iter_keys(str)

django-redis支持使用全局通配符的方式来检索或者删除key

>>> cache.set_many({'key_a':'A', 'key_b':'B'}, 600)
>>> cache.keys('key_*')
['key_a', 'key_b']

这个简单的写法将返回所有匹配的key,但在拥有很大数据量的数据库中这样做并不合适。

可以用iter_keys()方法取代keys(),返回匹配key的迭代器, 你可以使用迭代器高效的进行遍历。

>>> cache.iter_keys('key_')
<generator object algo at 0x7ffa9c2713a8>
>>> next(cache.iter_keys('key_')
"key_a"

原生客户端使用

在某些情况下你的应用需要进入原生 Redis 客户端使用一些 django cache 接口没有暴露出来的进阶特性. 为了避免储存新的原生连接所产生的另一份设置, django-redis 提供了方法 get_redis_connection(alias) 使你获得可重用的连接字符串.

>>> from django_redis import get_redis_connect
>>> redis_conn = get_redis_connextion('default') #建立和default对应的redis的联系
>>> pl = redis_conn.pipeline() #建立管道
>>> pl.setex('a', 60, 'A') #set(key, ttl, value)
>>> pl.setex('b', 50, 'B') #set(key, ttl, value)
>>> pl.exexute() #执行管道内的操作
>>> redis_conn.get('a').decode() #redis中数据以bytes格式保存,通过解码转字符串
'A'

参考