[TOC]
before
Django4.2.3 + win11 + python3.10
Django缓存框架的管档,写的很好,非常值得一读:https://docs.djangoproject.com/zh-hans/4.2/topics/cache/
Django缓存框架的核心目标:https://docs.djangoproject.com/zh-hans/4.2/misc/design-philosophies/#cache-framework
缓存的好处无需多言,所以Django提供了专门的缓存框架来支持各种缓存:
- 不同的缓存粒度,推荐程度由高到低排序:
- 指定视图缓存,粒度适中。
- 模板片段缓存,对模板文件的局部内容进行缓存,粒度较细。
- 全站缓存,粒度最大。
- 更低级别的缓存API,用来缓存Python中的对象(list、dict、模型对象...)。
- 不同的缓存方式,推荐程度由高到低排序:
- 第三方缓存数据库(redis、Memcache),专业的才是最好的嘛。另外,随着内存数据库的发展演变,Memcache不如redis用的多了。
- 本地文件缓存,将渲染好的字符串缓存到文件中,下次查询省了渲染的步骤了,内存不大的小站点非常有用。
- 本地数据库缓存,套路同本地文件缓存。
- 本地内存缓存,内存大了啥都好说。
- 虚拟缓存,用于开发,Django 带有一个实际上并不缓存的“虚拟”缓存——它只是实现了缓存接口而不做任何事情。
由于官档写的很详细了,本篇只做常用的配置和应用示例演示。
设置缓存
缓存系统需要少量的设置。也就是说,你必须告诉它你的缓存数据应该放在哪里 —— 是在数据库中,还是在文件系统上,或者直接放在内存中。这是一个重要的决定,会影响你的缓存的性能;是的,有些缓存类型比其他类型快。
缓存设置项位于你的配置文件的缓存配置中。这里有缓存配置所有可用值的说明。
缓存参数
这里来列一下公共的缓存参数:
TIMEOUT
:用于缓存的默认超时,以秒为单位。此参数默认为300
秒(5 分钟)。您可以设置TIMEOUT
为None
,默认情况下,缓存键永不过期。值0
会导致键立即过期(实际上是“不缓存”)。OPTIONS
:应该传递给缓存后端的任何选项。每个后端的有效选项列表会有所不同,第三方库支持的缓存后端会将其选项直接传递给底层缓存库。MAX_ENTRIES
:删除旧值之前缓存中允许的最大条目数。此参数默认为300
。CULL_FREQUENCY
:当缓存条目达到MAX_ENTRIES
时,剔除缓存中的比例,这个值必须是整数,默认是3,即剔除三分之一,如果是即剔除一半。存疑的是剔除的策略,我只查到了基于本地内存的缓存剔除策略是LRU,其它的貌似都是随机剔除。
KEY_PREFIX
: 一个字符串,将自动包含(默认添加)到 Django 服务器使用的所有缓存键中。VERSION
:Django 服务器生成的缓存键的默认版本号。KEY_FUNCTION
一个字符串,其中包含一个函数的虚线路径,该函数定义了如何将前缀、版本和密钥组合成最终的缓存密钥。
redis
现在redis数据库用的较多,所以放到最上面!但是django的缓存框架中并没有实现.....但django-redis
模块实现了,所以:
先下载django-redis
模块:
pip install django-redis
然后在settings.py
中进行配置:
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
# "LOCATION": "redis://IP:PORT/可选的数据库参数",
# "LOCATION": "redis://127.0.0.1:6379/0",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 100
},
"DECODE_RESPONSES": True, # True返回的数据自动decode
"PASSWORD": "", # 访问redis是否需要密码
}
}
}
具体的使用,参考:https://www.cnblogs.com/Neeo/articles/14269422.html
Memcache
现在由于Memcache用的不多了,这里仅作配置展示。
基于python-memcached模块连接memcache
在settings.py
中配置:
# 通过ip和port链接
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
# 通过sock文件链接
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
}
# 分布式的共享缓存配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
基于pylibmc模块连接memcache
在settings.py
中配置:
# 通过ip和port链接
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
}
# 通过sock文件链接
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
}
}
# 分布式的共享缓存配置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}
本地内存缓存
如果你的配置文件中没有指定其他缓存,那么这是默认的缓存。如果你想获得内存缓存的速度优势,但又不具备运行 Memcached 的能力,可以考虑使用本地内存缓存后端。这个缓存是每进程所有和线程安全的。
在配置文件中进行配置即可:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-xxxx', # 唯一标识的key
}
}
其他参数参考缓存参数章节。
额外的,我实际应用起来,发现使用这个内存缓存的话,将来项目部署到云服务器上之后,结合uwsgi时,在使用session缓存时出现问题,在uwsgi的多进程中,你就找不到session的缓存了,参考:https://www.cnblogs.com/Neeo/articles/10855542.html#nginx--uwsgi配置之后登录过程中找不到session
所以,我最终建议你如果要用到缓存的话,无论本地开发还是线上部署,都改用Redis作为缓存就好了,一劳永逸。
本地文件缓存
基于文件的后端序列化并保存每个缓存值作为单独的文件。
在配置文件中进行配置即可:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
# 如果您使用的是 Windows,请将驱动器号放在路径的开头
# 'LOCATION': 'c:/foo/bar',
}
}
其他参数参考缓存参数章节。
目录路径应该是绝对路径——也就是说,它应该从文件系统的根目录开始。是否在设置的末尾加上斜线并不重要。
确保此设置指向的目录存在并且可读可写,或者它可以由运行 Web 服务器的系统用户创建。
本地数据库缓存
Django 可以在数据库中存储缓存数据。如果你有一个快速、索引正常的数据库服务器,这种缓存效果最好。
在配置文件中进行配置即可:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table',
}
}
与其他缓存后端不同,数据库缓存不支持在数据库级别自动剔除过期条目。相反,每次调用add()
、set()
或时都会剔除过期的缓存条目。
完事之后,就要创建缓存表了:
python manage.py createcachetable
这将在您的数据库中创建一个表格,该表格具有 Django 的数据库缓存系统所期望的正确格式。表名取自 LOCATION
。
如果是多数据库的话,需要单独配置,参考管档吧:https://docs.djangoproject.com/zh-hans/4.2/topics/cache/#multiple-databases
虚拟缓存(用于开发模式)
最后,Django 带有一个实际上不是缓存的 “虚拟” 缓存,它只是实现缓存接口,并不做其他操作。
如果你有一个生产网站,在不同的地方使用了大量的缓存,但在开发/测试环境中,你不想缓存,也不想单独修改你的代码,那么这就很有用。
你只需要在配置文件中进行配置即可:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}
应用缓存
这里以本地内存缓存作为缓存配置,你可以在settings.py文件中添加如下配置:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-xxxx',
'OPTIONS': {
'MAX_ENTRIES': 300, # 最大缓存个数(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
}
}
一旦缓存设置完毕,就可以在项目中进行应用了。
局部视图缓存
settings.py中配置不变。
应用时有两种,分别是视图中以装饰器的形式和在路由上进行添加。
视图中应用缓存
views.py
:
import time
from django.shortcuts import render, HttpResponse, redirect
# 必须导入缓存装饰器
from django.views.decorators.cache import cache_page
@cache_page(5) # 缓存单位:秒
def index(request):
ctime = time.time()
return HttpResponse(ctime)
urls.py
:
from django.contrib import admin
from django.urls import path
from api import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]
浏览器访问的话,每五秒才会刷新一次,因为缓存时间是5秒。
在路由中应用缓存
urls.py
:
from django.contrib import admin
from django.urls import path
from django.views.decorators.cache import cache_page
from api import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', cache_page(5)(views.index)),
]
views.py
:
import time
from django.shortcuts import render, HttpResponse, redirect
# 必须导入缓存装饰器
# from django.views.decorators.cache import cache_page
# @cache_page(5) # 缓存单位是秒
def index(request):
ctime = time.time()
return HttpResponse(ctime)
浏览器访问效果跟上面的一样。
模板片段缓存
可以在模板中对局部进行更细粒度的缓存。
index.html
:
{% load cache %} <!-- 必须声明 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h3>未缓存的</h3>
<p>{{ ctime }}</p>
<p>{{ now }}</p>
<h3>使用缓存</h3>
<!-- 缓存内容 -->
{% cache 5 'unique-snowflake' %}
<p>{{ ctime }}</p>
<p>{{ now }}</p>
{% endcache %}
</body>
</html>
urls.py
:
from django.contrib import admin
from django.urls import path
# from django.views.decorators.cache import cache_page
from api import views
urlpatterns = [
path('admin/', admin.site.urls),
# path('index/', cache_page(5)(views.index)),
path('index/', views.index),
]
views.py
:
import time
import datetime
from django.shortcuts import render, HttpResponse, redirect
def index(request):
ctime = time.time()
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
return render(request, 'index.html', {"ctime": ctime, 'now': now})
更多参考管档吧:https://docs.djangoproject.com/zh-hans/4.2/topics/cache/#template-fragment-caching
全栈缓存
全站缓存的配置需要用到中间件和其他参数,settings.py
:
MIDDLEWARE = [
# 下面这个缓存中间件必须放在所有中间件的最上面
"django.middleware.cache.UpdateCacheMiddleware",
....
# 下面这个缓存中间件必须放在所有中间件的最下面
"django.middleware.cache.FetchFromCacheMiddleware",
]
# 我这里将cache缓存由本地内存缓存更换为了Redis
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://:@127.0.0.1:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"PASSWORD": "1234", # 密码,如果没有设置密码,这个参数可以注视掉
'MAX_ENTRIES': 300, # 最大缓存个数(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
}
}
}
# 默认超时时间是300秒,我们可以通过CACHE_MIDDLEWARE_SECONDS来修改
CACHE_MIDDLEWARE_SECONDS = 10
# 下面是关于key的,咱们这里保持默认就完了
CACHE_MIDDLEWARE_KEY_PREFIX = ""
# 用于存储的缓存别名,没想好的,指定个default就行
CACHE_MIDDLEWARE_ALIAS = "default"
urls.py
:
from django.contrib import admin
from django.urls import path
# from django.views.decorators.cache import cache_page
from api import views
urlpatterns = [
path('admin/', admin.site.urls),
# path('index/', cache_page(5)(views.index)),
path('index/', views.index),
]
views.py
:
import time
import datetime
from django.shortcuts import render, HttpResponse, redirect
def index(request):
ctime = time.time()
now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
return render(request, 'index.html', {"ctime": ctime, 'now': now})
index.html
:
{% load cache %} <!-- 必须声明 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
<h3>未缓存的</h3>
<p>{{ ctime }}</p>
<p>{{ now }}</p>
<h3>使用缓存</h3>
<!-- 缓存内容 -->
{% cache 5 'unique-snowflake' %}
<p>{{ ctime }}</p>
<p>{{ now }}</p>
{% endcache %}
</body>
</html>
注意,如果同时使用了全栈缓存和局部模板片段缓存,那么全栈缓存的优先级高。
see also: https://www.cnblogs.com/wupeiqi/articles/5246483.htmltml>