应先确认是否真需缓存,因SearchQuerySet或Q查询在数据量小、索引合理时执行很快;盲目缓存会带来过期管理、序列化开销及缓存穿透风险,须用django-debug-toolbar或EXPLAIN ANALYZE定位瓶颈。

缓存搜索结果前,先确认是否真需要缓存
很多场景下,SearchQuerySet(Django Haystack)或 Q 查询本身执行很快,尤其数据量小、索引合理时。盲目加缓存反而引入过期逻辑、序列化开销和缓存穿透风险。先用 django-debug-toolbar 或 EXPLAIN ANALYZE 确认瓶颈在 DB 还是业务逻辑——如果 DB 查询已
用 django.core.cache 为搜索结果做键值缓存
别用 cache_page 装饰器,它基于 URL,对带参数的搜索(如 ?q=python&category=web)容易键冲突或粒度太粗。应手动构造 cache key 并缓存序列化后的结果:
from django.core.cache import cache
from django.http import JsonResponse
<p>def search_view(request):
q = request.GET.get('q', '').strip()
category = request.GET.get('category', '')
if not q:
return JsonResponse({'results': []})</p><pre class='brush:python;toolbar:false;'>cache_key = f'search:{hash(q + category)}' # 避免长字符串作 key;实际建议用 hashlib.md5
cached = cache.get(cache_key)
if cached is not None:
return JsonResponse(cached)
# 执行真实搜索(例如:Article.objects.filter(Q(title__icontains=q) | Q(content__icontains=q)))
results = [...] # 序列化为 dict/list,不含 model 实例
cache.set(cache_key, results, timeout=60 * 15) # 15 分钟,避免 stale 数据影响用户体验
return JsonResponse(results)-
cache.set()的timeout建议设为固定值(如 900),不要依赖模型变更自动失效——搜索结果不需强一致性 - key 中避免直接拼接用户输入,防止 key 冲突或超长;用
hashlib.md5((q+category).encode()).hexdigest()[:12]更稳妥 - 缓存内容必须是纯 Python 数据结构(
dict/list/str/int),不能含QuerySet或 model 实例,否则 pickle 失败或反序列化出错
使用 Redis 作为缓存后端而非 locmem
locmem 缓存在多进程下不共享,本地开发可接受,但上线后必然失效。Django 默认的 LocMemCache 在 gunicorn 多 worker 场景下完全不可用。
配置示例(settings.py):
调用 Cutout.Pro 视觉处理 API 进行背景移除、人像抠图和照片增强,支持文件上传与图片 URL 输入。
立即学习“Python免费学习笔记(深入)”;
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
}
}
}
- 确保安装
django-redis和redis-py,仅靠django.core.cache自带后端无法支撑高并发搜索缓存 - Redis 的
GET/SET操作平均耗时 locmem 在大对象上反而比 DB 查询慢 - 别把整个 QuerySet 缓存——它会触发
__getstate__,可能意外加载关联字段,增大序列化体积
缓存失效策略要轻量,别监听模型信号
为每个 Article.save() 触发清空所有搜索缓存,会导致写放大和雪崩。更合理的做法是:
- 搜索缓存本身设较短 TTL(如 15 分钟),让 stale 数据自然过期
- 只在管理后台发布/下架文章时,手动调用
cache.delete_pattern('search:*')(需django-redis支持) - 对高频更新类目(如“热门标签”),单独缓存其 ID 列表,并在搜索时
filter(id__in=cached_ids),而非缓存完整结果
毫秒级响应的关键不在“绝对实时”,而在“可控延迟 + 低方差”。强行追求强一致,往往让缓存变成性能负优化。

















