每次用户请求页面时,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.cache是dafault缓存的快捷方式。
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'