W weiserv
← 返回博客

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 末尾的 /1Redis 数据库编号,下一节说为什么重要;
  • 密码从环境变量读,不要写进 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 单条昂贵查询结果

个人站最省事的是整页缓存 + 发布时清缓存:改动频率低(一天几次),
缓存命中率高,心智负担也最小。


小结

  1. Django 4.0+ 内置 Redis 后端,不必装 django-redis
  2. 缓存用独立 DB 号,避免 cache.clear() 误伤 session 等其他数据;
  3. "改了数据页面没变"的根治办法是把清缓存写进发布流程,不要靠记性;
  4. 缓存不是存储——Redis 清空后页面变慢可以接受,出错就是设计错了;
  5. 验证时记得 redis-cli -n <DB号>,查错库会得出"缓存没生效"的错误结论。

本文环境:Django 4.2 / Redis 5.0.7 / Python 3.11 / Ubuntu 22.04
配置与持久化策略为本站生产环境实际采用;具体参数以官方文档与你的实际负载为准。


系列阅读

广告位占位 · post-inline