HTTP 请求通常是数据库链接,数据处理,和模板渲染的。就处理数据而言,它的开销可比服务一个静态网站大多了。
请求开销在你的网站有越来越多的流量时是有意义的。这也使得缓存变得很有必要。通过缓存 HTTP 请求中 的查询结果,计算结果,或者是渲染上下文,你将会避免在接下来的请求中巨大的开销。这使得服务端的响应时间和处理时间变短。
Django 配备有一个健硕的缓存系统,这使得你可以使用不同级别的颗粒度来缓存数据。你可以缓存单一的查询,一个特定的输出视图,部分渲染的模板上下文,或者整个网站。缓存系统中的内容会在默认时间内被储存。你可以指定缓存数据过期的时间。
这是当你的站点收到一个 HTTP 请求时将会通常使用的缓存框架的方法:
1. 试着在缓存中寻找缓存数据
2. 如果找到了,就返回缓存数据
3. 如果没有找到,就执行下面的步骤:
1. 执行查询或者处理请求来获得数据
2. 在缓存中保存生成的数据
3. 返回数据
pip install django-redis
这是一个开源的项目,github地址是https://github.com/niwibe/django-redis
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"TIMTOUT":300,
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
设置一些常用的过期时间 给 redis
REDIS_TIMEOUT=7*24*60*60
CUBES_REDIS_TIMEOUT=60*60
NEVER_REDIS_TIMEOUT=365*24*60*60
from django.conf import settings
from django.core.cache import cache
#read cache user id
def read_from_cache(self, user_name):
key = 'user:id:'+user_name
value = cache.get(key)
if value == None:
data = None
else:
data = json.loads(value)
return data
#write cache user id
def write_to_cache(self, user_name):
key = 'user:id:'+user_name
cache.set(key, json.dumps(user_name), settings.NEVER_REDIS_TIMEOUT)
Django 提供了以下几个级别按照颗粒度上升的缓存排列:
Per-site cache:最高级的缓存。它缓存你的整个网站。
]Per-view cache:提供单一视图的缓存。
Template cache:允许你缓存模板片段。
Low-level cache API:提供了最高颗粒度。允许你缓存具体的查询或计算结果。
最简单的方法是使用缓存缓存整个网站。 你需要把'django.middleware.cache.UpdateCacheMiddleware' 和 'django.middleware.cache.FetchFromCacheMiddleware' 添加到你的 MIDDLEWARE_CLASSES 设置里, 如例子所示:
MIDDLEWARE_CLASSES = (
# 开始位置
'django.middleware.cache.UpdateCacheMiddleware',
.......
# 结束位置
'django.middleware.cache.FetchFromCacheMiddleware',
)
update'中间件,必须放在列表的开始位置,而fectch中间件,必须放在最后。
updata 中间件只实现了process_response() 方法
fecthc 中间件只实现了process_request() 方法
这样的设置就是和django的整个请求流程有关的:
当请求到来的时候 需要先经过一些列前面的验证 如果请求没有问题的时候, 到最后的fecthc中间件才开始去缓存中读取,如果读取到数据就从缓存中获取,然后在经过一些列的中间件后 到达uapdata中间件 对缓存中的内容判断是不是需要进行保存
这样才能保证完整的请求没有问题
默认的缓存的时间为5分钟 可以在settings中设置 TIMEOUT超时时间
使用的是 django.views.decorator.cache import cache_page
然后使用装饰器来完成缓存 @cache_page(60*15)
官方文档:说明的:
given a URL, try finding that page in the cache
if the page is in the cache:
return the cached page
else:
generate the page
save the generated page in the cache (for next time)
return the generated page
和站点缓存一样,视图缓存与 URL 无关。如果多个 URL 指向同一视图,每个URL将会分别缓存。
@cache_page(30, key_prefix='index1') 制定缓存的前缀
# 对视图进行缓存 第一个参数 缓存的时间 第二个参数缓存的前缀 在视图函数设定的 会优先于在settings中设定的
@cache_page(30, key_prefix='index1')
def index1(request):
print('进来1')
return render(request, 'demo001.html')
针对模板片段进行缓存
<!DOCTYPE html>
{% load cache %} # 加载cache
<html lang="en">
<head>
<meta charset="UTF-8">
<title>整站的缓存</title>
</head>
<body>
<h1>缓存03</h1>
{% cache 60 h2 request.user %} # 缓存的这个片段 第一个参数 时间(可以是模板变量 只要能解析成整数就行) 第二个是 变量名(不能是模板变量) 第三个是个用户名 针对不同的用户 缓存不同的简明
<h2>缓存003</h2>
{% endcache %}
</body>
</html>
缓存超时可以是模板变量,只要模板变量解析为整数值即可。
站点缓存会生效 这个和请求的流程有关
使用底层的cache api 这样可以随意的控制自己的缓存的颗粒度 更加细致的缓存的方式
form django.core.cache import cache
最基本的就是
set(key, value, timeout)
get(key) 如果不存在就返回一个None
不要在你的缓存中存储一个NOne 这样当返回的时候 你不知道 这个是没有命中缓存还是缓存中存储的值
使用add(key, value) 来增加缓存 如果存在的话 不会去更新缓存
不存在的话就会去设定这个缓存
如果你需要知道add()是否在缓存中存储了一个值,你可以检查返回值。
如果值存储,则返回True,否则返回False。
def index1(request):
# 可以这样使用cache
a = cache.get('a')
if not a: # 先去缓存中去获取这个值 如果这个值不存在就去吧这个值存在缓存中
b = 20
cache.set('a',b)
a = b
print(a)
return render(request, 'demo001.html')
cache.set_many({'a':100, 'b': 1000, "c": 300},timeout=5)
set_many(key, timeout) 也是可以设置过期时间的
cache.get_many(['a', 'b', 'c'])
返回的是:# OrderedDict([('a', 20), ('b', 12), ('c', 11)])
获取到的一个字典可以直接的去进行遍历 取值
key = cache.get_many(['a', 'b', 'c'])
for item, value in key.items():
print(item, value)
删除缓存
cache.delete('a')
cache.delete(['a','b]) 删除多个键
cache.clear() 删除所有的在redis中 不仅仅是在程序中设定的 小小的使用
使用 cache.incr("a") 加1
cache.decr("a") 减一
如果存储的不是一个可以转换为数字的 值 就会包错误的
Can't convert 'int' object to str implicitly
如果键不存在就会报错的
您还可以使用incr()或decr()方法分别递增或递减已存在的键。
默认情况下,现有高速缓存值将递增或递减1。
可以通过向增量/减量调用提供参数来指定其他增量/减量值。
如果您尝试增加或减少不存在的缓存键,则会引发ValueError错误
incr() / decr()方法不能保证是原子的。
在那些支持原子递增/递减(最明显的是memcached后端)的后端,
递增和递减操作将是原子的。然而,
如果后端本身不提供增量/减量操作,
则它将使用两步检索/更新来实现。
如果由缓存后端实现,您可以使用close()关闭与缓存的连接。
对于不实现close方法的缓存,它是一个无操作