对于非经常更新的服务器数据,若每次都从硬盘读取一次,会浪费服务器资源、拖慢响应速度,而且数据更新频率较高,服务器负担比较大。若保存到数据库,还需要额外建立一张对应的表存储数据。一个更好的方法是在Django中使用Redis进行缓存。
首先安装django-redis:
pip install django-redis
在setting文件中设置CACHES:
CACHES = {
'default':{
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION':"redis://you_host:you_port/1",
'TIMEOUT': 200, # NONE 永不超时
'OPTIONS':{
"PASSWORD":"you_passwd",#密码,没有可不设置
'CLIENT_CLASS': 'django_redis.client.DefaultClient', #redis-py 客户端
'PICKLE_VERSION': -1, # 插件使用PICKLE进行序列化,-1表示最新版本
'CONNECTION_POOL_KWARGS': {"max_connections": 100}, # 连接池最大连接数
'SOCKET_CONNECT_TIMEOUT': 5, # 连接超时
'SOCKET_TIMEOUT': 5, # 读写超时
}
#"KEY_PREFIX ":"test",#前缀
}
}
配置好后运行程序,进行测试:
引入库
>>>from django.core.cache import cache
>>>cache.set("test","abscd",30)
True
同时查看redis-cli客户端是否写入:
已经写入redis,说明配置没问题。
缓存框架通用的方法就是缓存视图函数,在需要进行缓存的视图函数文件中引入django.views.decorators.cache定义的装饰器cache_page,它可以自动缓存视图:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
在上面的例子里,cache_page 使用了一个参数:缓存过期时间,以秒为单位。my_view() 视图的结果将缓存15分钟。(注意,用 60 * 15 这样的方式编写,目的是方便阅读, 也就是15分钟),查看一下cache_page函数的定义:
def cache_page(timeout, *, cache=None, key_prefix=None):
"""
timeout:为上面设置的超时时间;
cache:可以指定使用哪个缓存;
key_prefix:缓存键值的前缀,如果setting里设置了KEY_PREFIX,它的键值将与KEY_PREFIX连接起来redis里缓存
可以这样使用,指定超时时间、指定使用哪个缓存、指定键名前缀
@cache_page(60 * 15, cache="special_cache",key_prefix="site1")
def my_view(request):
...
视图缓存还可以在url上进行。打开urls.py文件,引入相应的库,将需要缓存的url视图用cache_page包裹:
from django.views.decorators.cache import cache_page
urlpatterns = [
path('foo//' , cache_page(60 * 15)(my_view)),#缓存将保留15分钟
]
这样如果url (比如 /foo/23/ )已经被请求,那么随后的请求都将使用缓存,每个url都将被单独缓存。
在模板文件中使用缓存需要在顶部先引入 {% load cache %} ,然后就可以使用 {% cache %} 标签进行缓存操作,使用缓存标签至少需要提供两个参数,一个是超时时间、一个是键名,如:
{% load cache %}
{% cache 500 sidebar %}#500为缓存时间,sidebar为缓存片段名称
.. sidebar ..
{% endcache %}
如果想为每个登录用户单独缓存的话,可以这样:
{% load cache %}
{% cache 500 sidebar request.user.username %} #增加了用户这个参数,通常网站缓存还是得以用户为基准
.. sidebar for logged in user ..
{% endcache %}
注意:这里的缓存失效时间500可以为一个模板变量 ,{% cache my_var sidebar %} 可以从后端传递过来。
刚才介绍的都是基于页面的缓存,有时候我们并不想把页面所有内容都缓存,有些可变内容也不适合缓存,对于这些情况django提供了一些缓存api用于更细粒度的缓存,在django文档中所说,可以被pickle的python对象都可以缓存,这就包括:模型对象的字符串、字典、列表,大部分python对象都可以被pickle。
django.core.cache.caches
对caches的操作基本与对字典操作一样。
>>from django.core.cache import caches
>>cache1 = caches['myalias']
>>cache2 = caches['myalias']
cache1 is cache2
True
但是当我们访问一个不存在的键的时候,将会抛出InvalidCacheBackendError 错误。这时我们可以使用:
from django.core.cache import cache
cache.set(key, value, timeout=DEFAULT_TIMEOUT, version=None)
>> cache.set('my_key', 'hello, world!', 30)
cache.get(key, default=None, version=None)
>>> cache.get('my_key')
'hello, world!'
key 是一个字符串,value 可以pickle 的Python 对象。
timeout 参数是可选的,默认为 CACHES 中相应后端的 timeout 参数。timeout 设置为 None 时将永久缓存,timeout 为0将不缓存值。
如果对象不在缓存中,cache.get() 将返回 None。
建议不要在缓存中存储为 None 的值,因为你不能分辨是你存储的 None 值还是因为缓存命中返回的 None 值。
cache.add(key, value, timeout=DEFAULT_TIMEOUT, version=None)
在键不存在的时候,使用 add() 方法可以添加键。它与 set() 带有相同的参数,但如果指定的键已经存在,将不会尝试更新缓存。
>>> cache.set('add_key', 'Initial value')
>>> cache.add('add_key', 'New value')
>>> cache.get('add_key')
'Initial value'
#cache.get("add_key"," new_value"),get方法还可以像字典一样没有得到值的话返回一个默认值“new_value”
cache.get_or_set(key, default, timeout=DEFAULT_TIMEOUT, version=None)
如果你想得到键值或者如果键不在缓存中时设置一个值,可以使用 get_or_set() 方法。
>>> cache.get('my_new_key') # returns None
>>> cache.get_or_set('my_new_key', 'my new value', 100)
'my new value'
cache.get_many(keys, version=None)
cache.set_many(dict, timeout)
看示例:
>>> cache.set('a', 1)
>>> cache.set('b', 2)
>>> cache.set('c', 3)
>>> cache.get_many(['a', 'b', 'c'])#列表作为参数
{'a': 1, 'b': 2, 'c': 3}
>>> cache.set_many({'a': 1, 'b': 2, 'c': 3})#字典作为参数
>>> cache.get_many(['a', 'b', 'c'])
{'a': 1, 'b': 2, 'c': 3}
cache.delete(key, version=None)
cache.delete_many(keys, version=None)
>>> cache.delete('a') #删除一个键
>>>> cache.delete_many(['a', 'b', 'c'])#一次性删除多个
cache.incr(key, delta=1, version=None)
cache.decr(key, delta=1, version=None)
使用 incr() 或 decr() 方法来递增或递减一个已经存在的键的值,递增或递减一个不存在的缓存键,将会引发 ValueError 错误。
>>> cache.set('num', 1)
>>> cache.incr('num')
2
>>> cache.incr('num', 10)
12
>>> cache.decr('num')
11
>>> cache.decr('num', 5)
6
cache.touch(key, timeout=DEFAULT_TIMEOUT, version=None)
cache.touch() 为键设置一个新的过期时间。比如,更新一个键,过期时间为10秒钟
>>> cache.touch('a', 10)
True
默认情况下我们的对 (http://www.happyhong.cn/)这个链接的缓存对于所有访问者都是一样的,不能针对不同用户代理进行区别缓存,如果想使用基于cookies、user-agent的不同进行缓存,就需要使用django提供的 django.views.decorators.vary.vary_on_headers() 视图装饰器,像这样:
from django.views.decorators.vary import vary_on_headers
@vary_on_headers('User-Agent')
def my_view(request):
...
Django 自带的缓存中间件将为每一个用户代理即user-agent缓存一个独立的页面版本,传递给 vary_on_headers 的头是不区分大小写的;“User-Agent” 和 “user-agent” 是一样的。
可以传递多个头参数给 vary_on_headers():
@vary_on_headers('User-Agent', 'Cookie')
def my_view(request):
...
这就意味着要根据每个用户代理和 cookie 的组合来获取它自己的缓存值。
from django.views.decorators.cache import cache_control
@cache_control(private=True)
def my_view(request):
关于cache_control后续再更新吧,更多爬虫、django相关、软件安装请移步从今天开始种树。。。