Django 4.2 配置 Redis 缓存:不用装 django-redis,以及「改了数据页面没变」的坑
Django 4.2 + Redis 缓存:配置与三个坑
给 Django 站点接 Redis 做缓存,很多教程第一句还是 pip install django-redis。
Django 4.0 之后已经内置了 Redis 后端,标准库式配置就够了,少一个依赖。
本站(Django 4.2,MySQL + Redis)就是这么配的。这篇讲三件事:怎么配、
为什么缓存要单独用一个 DB 号、以及最常遇到的"改了数据页面却没变"怎么根治。
一、结论先行
| 问题 | 结论 |
|---|---|
要不要装 django-redis? |
不需要(Django 4.0+ 内置 RedisCache),除非你要用它特有的高级功能 |
| 缓存该放哪个 DB? | 单独一个号(如 /1),别和 session 等其他用途混 |
| 改了数据页面没变? | 缓存在作怪 → 发布/改动后执行 cache.clear() |
| Redis 宕了会不会丢数据? | 缓存不是存储,丢了只应影响速度,不应影响正确性 |
二、最小配置(生产用 Redis,本地用内存)
settings.py 里按环境分两套——本地开发没必要起 Redis:
import os
if os.getenv("DJANGO_ENV") == "production":
_redis_pw = os.environ["DJANGO_REDIS_PASSWORD"] # 密码走环境变量,别硬编码
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": f"redis://:{_redis_pw}@127.0.0.1:6379/1",
}
}
else:
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.locmem.LocMemCache",
}
}
要点:
- 后端是
django.core.cache.backends.redis.RedisCache(内置,无需额外安装); LOCATION末尾的/1是 Redis 数据库编号,下一节说为什么重要;- 密码从环境变量读,不要写进 settings 提交到仓库。
三、为什么缓存要单独用一个 DB 号
Redis 默认有 16 个逻辑库(编号 0~15),用 SELECT n 切换。
把缓存放在 /1 而不是默认的 /0,是为了隔离:
cache.clear() 会清空整个缓存库——不是只删你刚改的那一条。
如果 session、限流计数、任务队列跟缓存挤在同一个 DB 里,一次清缓存会把它们连锅端
(最直观的后果:所有登录用户被踢下线)。
本站把缓存放在 /1,就是为了在需要清缓存时只影响缓存。
反过来也要注意:如果你确实把 session 也存 Redis,请给它另一个 DB 号,
并在flushdb/cache.clear()之前先确认清的是哪一个库。
四、坑 1:改了数据,页面却没变(最高频)
现象
后台明明改了文章、发了新版,刷新页面还是旧内容;
换浏览器、清浏览器缓存都没用。
根因
模板或视图被缓存住了,数据库里已经是新数据,但返回的是缓存的旧渲染结果。
本站发布文章后如果不清缓存,前台就会一直显示旧列表。
根治:发布/改动后清缓存
from django.core.cache import cache
cache.clear()
在 Django shell 里:
python manage.py shell -c "from django.core.cache import cache; cache.clear(); print('cache cleared')"
本站的发布脚本把这一步内置在发布流程末尾了——每次发布成功自动执行,
输出里能看到 cache cleared。把它变成流程的一部分,而不是靠人记得,
这是这类问题唯一可靠的解法。
更精细的做法
cache.clear() 是"全清",简单粗暴。如果只想失效一部分,应按 key 删除:
cache.delete("post_list") # 删指定 key
cache.delete_many(["a", "b"]) # 批量删
或者给缓存加版本号,改版时整体升版本:
cache.set("post_list", data, version=2)
cache.get("post_list", version=2)
五、坑 2:把缓存当存储用
缓存的正确心智模型是:丢了只会变慢,不应变错。
判断标准很简单——如果你的代码在"Redis 里没有这个 key"时会出错,
那它就已经不是缓存,而是把 Redis 当数据库用了。
本站的缓存背后是 MySQL 里的文章数据,Redis 挂掉或清空后,
页面会重新查库重建缓存,内容不会错,只是第一下慢一点。
对应到 Redis 持久化策略上,本站保持 RDB 默认策略:
save 900 1 # 15 分钟内有 1 次改动就落盘
save 300 10
save 60 10000
没有开 AOF——因为对缓存来说,RDB 的分钟级丢失完全可接受,
为它付出 AOF 的写入开销不划算。是否开 AOF,取决于你把 Redis 当缓存还是当存储。
六、怎么验证缓存真的生效
三个层面各查一次,30 秒确认:
# 1) Redis 里有没有 key
redis-cli -n 1 DBSIZE # 注意 -n 1 对应配置里的 /1
redis-cli -n 1 KEYS '*' | head
# 2) Django 侧能不能写入/读出
python manage.py shell -c "
from django.core.cache import cache
cache.set('probe', {'ok': True}, 30)
print(cache.get('probe'))
"
# 3) 页面层面:改一条数据 → 刷新看是否变化 → 清缓存 → 再刷新
如果 DBSIZE 一直是 0 且 cache.set/get 正常,
多半是你查错了 DB 号(配置写 /1,却用默认 0 去看)。
七、缓存粒度怎么选
| 粒度 | 用法 | 适用 |
|---|---|---|
| 整页缓存 | @cache_page(60 * 15) 装饰视图 |
变化不频繁的公开页 |
| 片段缓存 | 模板里 {% cache %}(需 {% load cache %}) |
页面局部很贵、整体不宜缓存 |
| 对象/查询缓存 | 手动 cache.get/set |
单条昂贵查询结果 |
个人站最省事的是整页缓存 + 发布时清缓存:改动频率低(一天几次),
缓存命中率高,心智负担也最小。
小结
- Django 4.0+ 内置 Redis 后端,不必装
django-redis; - 缓存用独立 DB 号,避免
cache.clear()误伤 session 等其他数据; - "改了数据页面没变"的根治办法是把清缓存写进发布流程,不要靠记性;
- 缓存不是存储——Redis 清空后页面变慢可以接受,出错就是设计错了;
- 验证时记得
redis-cli -n <DB号>,查错库会得出"缓存没生效"的错误结论。
本文环境:Django 4.2 / Redis 5.0.7 / Python 3.11 / Ubuntu 22.04
配置与持久化策略为本站生产环境实际采用;具体参数以官方文档与你的实际负载为准。
系列阅读
- 证书续期别再靠人肉:acme.sh + DNSPod 通配符证书自动续期与排障实录——同属"配一次、别再惦记"的生产配置。