cache.get() 总是返回 None 的根本原因是缓存后端未真正连接 Redis,Django 静默降级为 LocMemCache;必须确保 CACHES'default' 为 django_redis.cache.RedisCache、LOCATION 为 redis://127.0.0.1:6379/1、OPTIONS 含 "CLIENT_CLASS": "django_redis.client.DefaultClient",并用 shell 验证 cache.set/get。
cache.get() 总是返回 None?先确认缓存后端是否真正连上 Redis
不是装了 django-redis 就等于 redis 生效了。django 默认静默降级到 locmemcache,cache.set() 不报错、cache.get() 却返回 none,八成是配置没走通。
-
CACHES['default']['BACKEND']必须是django_redis.cache.RedisCache,不能写成django.core.cache.backends.redis.RedisCache(后者是 Django 5.0+ 原生支持,但当前稳定版仍依赖django-redis) -
LOCATION推荐用 URL 格式:redis://127.0.0.1:6379/1;别用localhost—— Docker 或某些云环境 DNS 解析可能卡住 - 如果 Redis 开密码,URL 中必须带
:mypass@,例如:redis://:secret123@127.0.0.1:6379/1 -
OPTIONS里漏掉"CLIENT_CLASS": "django_redis.client.DefaultClient",会导致序列化失败,cache.get()静默返回None
验证方法:进 python manage.py shell,执行 from django.core.cache import cache; cache.set('test', 'ok', 30); print(cache.get('test'))。若输出 None,立刻检查 cache.client.connection_pool 是否能 get_connection()。
cache_page 装饰器不生效?中间件顺序和视图类型是关键
@cache_page 看似简单,但失效原因往往不在 Redis,而在请求链路没走对。
- 只对函数视图生效;类视图必须用
@cache_page(60*15)(MyView.as_view())包裹as_view()调用,不能直接装饰类定义 -
MIDDLEWARE顺序必须严格:UpdateCacheMiddleware放最前,FetchFromCacheMiddleware放最后,且中间不能插其他中间件(如CommonMiddleware必须夹在两者之间) - GET 参数不同会生成不同缓存键,但像
csrf_token、动态时间戳这类前端注入参数会让每次请求键都变,缓存形同虚设 - 登录态页面慎用
@cache_page—— 它默认不缓存 Cookie 或 Authorization 头,用户看到的可能是别人的数据
如何安全地把 Session 存进 Redis?别只配 ENGINE
Session 存 Redis 不只是改 SESSION_ENGINE,否则用户频繁登出或状态丢失,问题出在生命周期没对齐。
- 必须设置
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'或更稳妥的'django.contrib.sessions.backends.cached_db'(双写缓存+DB,防 Redis 故障丢 session) - Redis 的 key 默认永不过期,但 Django Session 有自身过期逻辑(默认 1209600 秒),需显式让 Redis 尊重它 ——
django-redis会自动处理,前提是LOCATION指向的 Redis DB 没被其他进程清空 - 避免多个项目共用同一个 Redis DB:用不同 DB 编号(如
/1存缓存、/2存 session),或加KEY_PREFIX隔离 - 测试时用
redis-cli -n 2 keys "session:*"直接查 session 键是否存在,比看日志更可靠
想绕过 Django 缓存层直连 Redis?用 get_redis_connection
当你要存非缓存语义的数据(比如任务队列、分布式锁、排行榜),cache.set() 不合适 —— 它带序列化、前缀、过期封装,还可能被缓存中间件干扰。
- 用
from django_redis import get_redis_connection获取原生连接:r = get_redis_connection("default") - 注意返回值是 bytes:
r.get("key")返回b"value",需要.decode()才能当字符串用 - 如果要存复杂对象,自己序列化(推荐
json.dumps(...).encode()),别依赖cache的 pickle —— 安全风险高,且跨 Python 版本不兼容 - 连接池参数(如
max_connections)要在CACHES['default']['OPTIONS']['CONNECTION_POOL_KWARGS']里配,否则每调用一次get_redis_connection都可能新建连接
真正麻烦的不是连上 Redis,而是缓存键设计、失效策略和数据一致性——这些没法靠配置解决,得结合业务场景手动控制。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











