Django的缓存
动态网站的不足之处体现在“动态”上。每请求一个页面,Web 服务器都要做各种计算,为了让用户可以看到页面,要查询数据库、渲染模板,还要执行一些业务逻辑。从消耗方面来看,这个过程比从文件系统中读取一个文件要耗资源。
Django 提供了一个强健的缓存系统,能把动态页面保存起来,不用每次请求都重新生成。为了便于使用,Django 提供的缓存分为不同的粒度层次,可以缓存特定视图的输出、可以只缓存不易生成的片段,也可以缓存整个网站。
配置缓存
开发调试
Django提供了一个虚拟的缓存,它并不是真正的缓存,只是实现了缓存接口。
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}
基于本地内存的缓存
如果你的本地主机内存够大够快,也可以直接使用它作为缓存。配置如下:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}
文件缓存
基于文件的后端会序列化各个缓存值,将其存入单独的文件
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': 'c:/foo/bar',
}
}
数据库缓存
Django 可以把缓存数据存入数据库。如果数据库服务器的索引稳定快速,这样做效果最好。以数据表为缓存后端的步骤如下:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table',
}
}
但是在某些情况下,还是有一些用途的,比如你有一个高速、高效索引的数据库。
注意,创建缓存的数据库表使用的语句:
python manage.py createcachetable
Memcached
Memcached是Django原生支持的缓存系统,速度快,效率高。Memcached是一种基于内存的缓存服务,起初是为了解决LiveJournal.com的负载问题而开发的,后来由Danga开源。 它被类似Facebook和维基百科这种大型网站使用,用来减少数据库访问次数,显著地提高了网站的性能。
Memcached会启动一个守护进程,并分配单独的内存块。其主要工作就是为缓存提供一个快速的添加,检索,删除的接口。所有的数据直接存储在内存中,所以它不能取代数据库或者文件系统的功能。如果你对缓存很熟悉,这些内容都很好理解。
需要注意的是:
- Memcached不是Django自带的软件,而是一个独立的软件,需要你自己安装、配置和启动服务;
- Memcached安装好了后,还要安装Python操作Memcached的依赖库,最常用的是python-memcached和pylibmc;
- 上面两个条件都满足了后,还要在Django中进行配置。
配置方法:
-
根据你安装的Python依赖库不同,将CACHES的BACKEND设置为
django.core.cache.backends.memcached.MemcachedCache 或者 django.core.cache.backends.memcached.PyLibMCCache
-
设置LOCATION为你的Memecached守护进程所在的主机IP和进程端口,格式为ip:port的字符串。或者unix:path的形式,在Unix操作系统中。
下面是一个参考例子,Memcached运行在localhost (127.0.0.1) port 11211
,使用了python-memcached
库:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
下面的Memcached运行在本地的Unix socket上:/tmp/memcached.sock
,依赖python-memcached
:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
}
下面的Memcached运行在/tmp/memcached.sock
,不带unix:/
前缀,依赖pylibmc库:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
}
}
Memcached支持分布式服务,可能同时在几台机器上运行,将它们的IP地址都加入到LOCATION中,如下所示:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:21423',
'172.19.26.244:11213',
]
}
}
基于内存的缓存系统有个明显的缺点就是断电数据丢失,尤其是Memcached这种不支持序列化的缓存,所以请大家务必要注意数据的安全性。
缓存参数
上述每一个缓存后端都可以设置一些额外的参数来控制缓存行为,可以设置的参数如下:
-
TIMEOUT:缓存的默认过期时间,以秒为单位,默认是300秒None表示永远不会过期。设置成0将造成缓存立即失效(缓存就没有意义了)。
-
OPTIONS:可选参数,根据缓存后端的不同而不同。
-
KEY_PREFIX:Django服务器使用的所有缓存键的字符串。
-
VERSION:由Django服务器生成的默认版本号。
-
KEY_FUNCTION:一个字符串,其中包含一个函数的点路径,该函数定义了如何将前缀,版本和密钥组合成最终缓存密钥。
文件缓存是参数配置实例:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', #指定缓存使用的引擎
'LOCATION': '/var/tmp/django_cache', #指定缓存的路径
'TIMEOUT':300, #缓存超时时间(默认为300秒,None表示永不过期)
'OPTIONS':{
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
}
}
}
Django中的缓存应用
缓存全站
缓存系统最简单的使用方法是缓存整个网站。
这需要额外将’django.middleware.cache.UpdateCacheMiddleware’和’django.middleware.cache.FetchFromCacheMiddleware’添加到MIDDLEWARE设置中,如下所示:
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
]
注意: update
中间件必须放在列表的开始位置,而fectch
中间件,必须放在最后。 这是Django使用中间件的规则,它们是有顺序关系的。
然后,添加下面这些需要的参数到settings文件里:
CACHE_MIDDLEWARE_ALIAS : 用于存储的缓存的别名
CACHE_MIDDLEWARE_SECONDS : 每个page需要被缓存多少秒.
CACHE_MIDDLEWARE_KEY_PREFIX : 密钥前缀
缓存视图
另一个使用缓存框架的方法是对视图的输出进行缓存。在django.views.decorators.cache
定义了一个自动缓存视图响应结果的装饰器cache_page
,使用非常简单:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
cache_page
接受一个参数:timeout,秒为单位。在上例中,my_view()
视图的结果将被缓存15分钟(为了提高可读性写成了60 * 15)
和整站缓存一样,一个URL对应一个键。如果多个URL指向同一视图,每个URL将会分别缓存。 继续my_view的例子,如果URLconf如下所示:
urlpatterns = [
url(r'^foo/([0-9]{1,2})/$', my_view),
]
那么发送到/foo/23/
和/foo/1/
的请求会被分别缓存。但是一旦一个明确的URL(例如/foo/23/
) 已经被请求过了, 之后再度发出的指向该URL的请求将使用缓存的内容。
cache_page
也可以使用一些额外的参数,比如cache,这个参数指示具体使用的缓存后端。
@cache_page(60 * 15, cache="special_cache")
def my_view(request):
...
还可以采用可选的关键字参数key_prefix
在每个视图中指定具体的缓存前缀,如下所示:
@cache_page(60 * 15, key_prefix="site1")
def my_view(request):
...
缓存模板片段
我们还可以使用cache
模板标签来缓存模板的一个片段。要使用这个标签,首先要在模版的顶部位置添加{% load cache %}
。
模板标签{% cache %}
将在设定的时间内,缓存标签块中包含的内容。它最少需要两个参数:缓存时间(以秒为单位)以及给缓存片段起的名称。像这样:
{% load cache %}
{% cache 500 sidebar %}
.. sidebar ..
{% endcache %}
还可以依据片段内的动态内容缓存多个版本。如上个例子中,可以给站点的每个用户生成不同版本的sidebar缓存。 只需要给{% cache %}
标签再传递一个参数来标识区分这个缓存片段,如下所示:
{% load cache %}
{% cache 500 sidebar request.user.username %}
.. sidebar for logged in user ..
{% endcache %}
缓存超时参数可以是个模板变量,只要模板变量可以解析为整数值即可。例如,如果模板变量my_timeout设置为值600,则以下两个示例是等效的:
{% cache 600 sidebar %} ... {% endcache %}
{% cache my_timeout sidebar %} ... {% endcache %}
实例:
views视图函数
from django.views.decorators.cache import cache_page
import time
from .models import *
def index(request):
t=time.time() #获取当前时间
bookList=Book.objects.all()
return render(request,"index.html",locals())
模板(index.html):
{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3 style="color: green">不缓存:-----{{ t }}</h3>
{% cache 2 'name' %}
<h3>缓存:-----:{{ t }}</h3>
{% endcache %}
</body>
</html>
前后端分离
设置值跟取值:
from django.core.cache import cache
# 设置缓存
cache.set('test_data',{'name':'linwow'},5)
# 获取缓存
cache.get('test_data')
高级用法
rom django.core.cache import cache
# 设置:cache.set(键,值,有效时间)
cache.set('my_key', 'hello, world!', 30)
cache.add('add_key', 'New value')
cache.set_many({'a': 1, 'b': 2, 'c': 3})
# 获取:cache.get(键)
cache.has_key('v') #判断key为v是否存在
cache.get('my_key')
cache.get('my_key', 'has expired')
cache.get_many(['a', 'b', 'c'])
# 删除:cache.delete(键)
cache.delete('key')
cache.delete_many(['a', 'b', 'c'])
# 清空:cache.clear()
cache.clear()
# 增加时间
cache.set('num', 1)
cache.incr('num') # 每次默认增加1秒
cache.incr('num', 10) # 在原来的时间上增加10秒
# 减少时间
cache.decr('num') # 每次默认减少一秒
cache.decr('num', 5) # 在原来的时间上减去5秒
# 禁用客户端缓
# 如果你不在视图中使用缓存,服务器端是肯定不会缓存的,然而用户的客户端如浏览器还是会缓存一些数据,这时你可以使用never_cache禁用掉客户端的缓存。
from django.views.decorators.cache import never_cache
@never_cache
def index(request):
pass
# views.py
from django.views.decorators.cache import never_cache
class MyTime(View):
@never_cache
def get(self, request):
timer = time.time()
return HttpResponse(timer)
@never_cache
def myFun(request):
timer = time.time()
return HttpResponse(timer)