本文目录导读:
Django 的缓存系统非常灵活,支持多种后端(内存、数据库、文件系统、Redis/Memcached 等),以下是详细的配置和使用指南。
核心配置(settings.py)
首先在 settings.py 中设置 CACHES 字典:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 本地内存缓存(默认)
'LOCATION': 'unique-snowflake', # 用于区分多个内存缓存的名称
'TIMEOUT': 300, # 默认超时时间:300秒(5分钟)
'OPTIONS': {
'MAX_ENTRIES': 300, # 最大缓存条目数
'CULL_FREQUENCY': 3, # 达到 MAX_ENTRIES 时,删除三分之一条目
}
}
}
常用缓存后端配置
1 文件系统缓存
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache', # 必须是绝对路径
}
}
2 数据库缓存
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table', # 数据库表名
}
}
# 需要创建缓存表:python manage.py createcachetable
3 Memcached 缓存
# 方式1:使用 python-memcached 库
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
'LOCATION': [
'127.0.0.1:11211', # 单实例
# 也可以配置多台服务器
# '10.0.1.10:11211',
# '10.0.1.11:11211',
],
'TIMEOUT': 300,
}
}
# 方式2:使用 pylibmc 库(性能更好)
# CACHES = {
# 'default': {
# 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
# 'LOCATION': '127.0.0.1:11211',
# }
# }
4 Redis 缓存(最推荐)
# 需要安装:pip install django-redis
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1', # Redis URL
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'SOCKET_CONNECT_TIMEOUT': 5, # 连接超时
'SOCKET_TIMEOUT': 5, # 读写超时
'PASSWORD': 'yourpassword', # 如果有密码
'PARSER_CLASS': 'redis.connection.HiredisParser', # 提高性能
'CONNECTION_POOL_CLASS': 'redis.BlockingConnectionPool',
'CONNECTION_POOL_CLASS_KWARGS': {
'max_connections': 100,
'timeout': 20,
},
}
}
}
# 也可以配置多个 Redis 实例(主从、哨兵等)
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': [
'redis://127.0.0.1:6379/1',
'redis://127.0.0.1:6378/1', # 备用
],
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.SentinelClient', # 哨兵模式
'SENTINEL_KWARGS': {'master_name': 'mymaster'},
}
}
}
多缓存配置
可以同时配置多个缓存后端,用于不同场景:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379',
'TIMEOUT': 300,
},
'session': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'session_cache_table',
'TIMEOUT': 86400, # 24小时
},
'staticfiles': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_static_cache',
'TIMEOUT': 86400 * 30, # 30天
}
}
缓存的时间
全局设置与局部设置:
# settings.py 中全局设置 CACHE_MIDDLEWARE_ALIAS = 'default' # 中间件使用的缓存别名 CACHE_MIDDLEWARE_SECONDS = 600 # 缓存时间(秒) CACHE_MIDDLEWARE_KEY_PREFIX = 'myapp' # 缓存键前缀 # 使用 site 框架时自动设置 CACHE_MIDDLEWARE_ANONYMOUS_ONLY = True # 仅缓存匿名用户
缓存键前缀设置
# 方案1:在配置中设置 KEY_PREFIX
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379',
'KEY_PREFIX': 'mysite_' # 所有缓存键都会带此前缀
}
}
# 方案2:使用 site 框架自动添加站点前缀
INSTALLED_APPS = [
'django.contrib.sites',
]
# 设置 SITE_ID 后,缓存键会自动包含站点标识
版本控制
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379',
'VERSION': 1, # 整数版本号
'KEY_FUNCTION': 'django.core.cache.utils.make_key',
'VERSION_BASED_KEY_FUNCTION': 'django.core.cache.utils.default_key_func',
}
}
# 运行时改变版本号(会清空之前版本的缓存)
from django.core.cache import cache
cache.version = 2 # 当前版本
实际使用示例
1 视图缓存(装饰器)
from django.views.decorators.cache import cache_page
@cache_page(60 * 15) # 缓存15分钟
def my_view(request):
# 耗时操作
return render(request, 'template.html')
# 也可以用在 URLconf 中
from django.views.decorators.cache import cache_page
urlpatterns = [
path('my_view/', cache_page(60 * 15)(my_view)),
]
2 片段缓存(模板中使用)
{% load cache %}
{% cache 500 "sidebar" %}
{# 这里的内容会被缓存500秒 #}
{% for item in items %}
<li>{{ item.name }}</li>
{% endfor %}
{% endcache %}
{% cache 3600 "sidebar" request.user.username %}
{# 基于用户的缓存 #}
<div>欢迎 {{ request.user.username }}</div>
{% endcache %}
3 低级别缓存 API
from django.core.cache import cache
# 设置缓存
cache.set('my_key', 'my_value', timeout=300) # 5分钟
cache.set_many({'key1': 'val1', 'key2': 'val2'}, timeout=60)
# 获取缓存
value = cache.get('my_key')
values = cache.get_many(['key1', 'key2'])
# 使用 get_or_set
value = cache.get_or_set('expensive_key', 'default_value', 300)
# 原子操作(增加/减少)
cache.incr('counter', delta=1)
cache.decr('counter', delta=1)
# 获取后删除(原子操作)
value = cache.get_and_delete('my_key')
# 删除缓存
cache.delete('my_key')
cache.delete_many(['key1', 'key2'])
# 清空整个缓存(谨慎使用)
cache.clear()
# 检查键是否存在
has_key = cache.has_key('my_key')
# 手动设置超时时间
cache.touch('my_key', timeout=600) # 重置为10分钟
# 设置默认超时(使用配置中的默认值)
cache.set('key', 'value') # 使用全局TIMEOUT
# 批量操作
cache.set('key1', 'val1', 60)
cache.set('key2', 'val2', 120)
# cache.set_many({'key1': 'val1', 'key2': 'val2'}, timeout=300) # 统一超时
# 使用键前缀
from django.core.cache import cache
cache.set('raw_key', 'value')
# 实际存储时为 'mysite_:1:raw_key'(假设前缀为 mysite_,版本为1)
# 设置过期时间的 Unix 时间戳
import time
cache.set('key', 'value', timeout=int(time.time()) + 3600) # 1小时后过期
# 检查缓存是否可用
cache.ping() # 如果可用返回 True,否则抛出异常
数据库查询缓存示例
from django.core.cache import cache
from .models import Article
def get_article_list():
# 尝试从缓存获取
articles = cache.get('article_list')
if articles is None:
# 缓存未命中,从数据库查询
articles = list(Article.objects.all().select_related('author'))
# 存入缓存,设置超时时间
cache.set('article_list', articles, 300)
return articles
# 更简洁的方式
def get_article_list_v2():
articles = cache.get_or_set(
'article_list',
lambda: list(Article.objects.all().select_related('author')),
300 # 缓存5分钟
)
return articles
信号驱动缓存失效
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from django.core.cache import cache
from .models import Article
@receiver(post_save, sender=Article)
@receiver(post_delete, sender=Article)
def clear_article_cache(sender, **kwargs):
# 文章保存或删除时清除相关缓存
cache.delete('article_list')
cache.delete(f'article_detail_{kwargs["instance"].id}')
# 也可以在 post_save 信号中更新缓存
@receiver(post_save, sender=Article)
def update_article_cache(sender, instance, created, **kwargs):
if created:
# 添加到缓存
article_list = cache.get('article_list') or []
article_list.append(instance)
cache.set('article_list', article_list, 300)
else:
# 更新缓存
cache.delete('article_list')
缓存中间件配置
# settings.py 添加中间件
MIDDLEWARE = [
'django.middleware.cache.UpdateCacheMiddleware', # 放在最前面
# ... 其他中间件 ...
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware', # 放在最后
]
CACHE_MIDDLEWARE_ALIAS = 'default'
CACHE_MIDDLEWARE_SECONDS = 600
CACHE_MIDDLEWARE_KEY_PREFIX = '' # 可选前缀
缓存键的构造
# 默认键函数生成:key_prefix:version:key
# mysite_:1:article_list
# 自定义键函数
def my_key_func(key, key_prefix, version):
return f'{key_prefix}:{version}:{key}'
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379',
'KEY_FUNCTION': 'my_app.cache.my_key_func', # 自定义键函数
}
}
性能与监控
# 启用缓存统计
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
'SETTINGS': {
'CACHE_HIT_RATIO': True, # 启用命中率统计
}
}
}
}
# 获取缓存统计信息
from django_redis import get_redis_connection
connection = get_redis_connection('default')
info = connection.info()
print(info['keyspace_hits'], info['keyspace_misses']) # 命中/未命中
常见问题与最佳实践
- 缓存失效策略:对于频繁更新的数据,使用较短的超时时间;对于不常变化的数据,使用较长的超时时间
- 键命名规范:使用有意义的、唯一的键名,避免冲突
- 版本管理:代码更新后,考虑增加缓存版本号以强制刷新
- 异常处理:缓存后端不可用时,应有降级策略(如直接查询数据库)
- 监控:监控缓存命中率,及时调整策略
- 安全性:不要缓存敏感信息(密码、个人隐私等)
选择合适的缓存后端取决于你的项目规模、性能需求和可用的基础设施,对于大多数中小型项目,Redis 是最推荐的选项,它提供了高性能、持久化选项和丰富的数据结构支持。
标签: Redis