知其然,知其所以然
Django 2026-09-30

缓存失效时间与并发请求

实测缓存过期与并发:get_or_set 20 线程并发时 compute 执行 20 次;cache.add 互斥只算 1 次;计算 200 ms、TTL 1 秒时阻塞式回源 p99 205 ms,stale-while-revalidate p99 0.3 ms;set 重置 TTL;缓存里读-改-写会 lost update。

Django 缓存 过期时间 并发 真实验证 动画演示
Django 2026-09-30

使用 Redis 缓存 Session

实测用 Redis 缓存 session:key 格式 :1:django.contrib.sessions.cache<key>、TTL 14 天、pickle 值;Redis 被清空后 cache 后端全员登出而 cached_db 不受影响;maxmemory + allkeys-lru 会把 session 一起淘汰;本机三种后端每请求耗时 0.41 / 0.41 / 0.40 ms(无差异)。

Django session Redis 缓存 真实验证 动画演示
Django 2026-09-30

数据库查询次数测试

用真实的 manage.py test 演示查询次数测试:assertNumQueries 精确断言与 N+1 失败时列出每条 SQL 的报错;CaptureQueriesContext 上界断言;TestCase 里 atomic 是 SAVEPOINT、TransactionTestCase 里是 BEGIN / COMMIT。

Django 测试 assertNumQueries 查询次数 真实验证 动画演示
Django 2026-09-30

N+1 查询问题实战

在 admin 列表页上实战 N+1:admin 会自动对 list_display 里的外键做 select_related,但 __str__ 里更深的外键(author.category)仍然每行一次(55 次查询 / 50 行);list_select_related 之后固定 5 次;10/50/200 行的查询数 15/55/105(admin 每页 100 条)。

Django N+1 admin list_select_related 真实验证 动画演示
Django 2026-09-30

Django Debug Toolbar 分析慢查询

用 Django Debug Toolbar 的 SQL 面板看 N+1 页面:101 次查询、100 次 similar / 100 次 duplicate,并带调用栈;select_related 后只剩 1 次;同一页面有无工具栏的请求耗时 10.31 ms → 22.24 ms。

Django Debug Toolbar 慢查询 N+1 真实验证 动画演示
Django 2026-09-30

iterator() 降低查询集内存占用

遍历 20 万行:list() 与直接 for 峰值内存 155.0 MiB,iterator() 1.7 MiB、chunk_size=500 时 0.5 MiB;PostgreSQL 上同样;iterator() 与 prefetch_related 一起用必须给 chunk_size;iterator() 之后不缓存。

Django iterator 内存 QuerySet 真实验证 动画演示
Django 2026-09-30

Django Signal 的发送与接收

Signal 的基本行为:按连接顺序调用并返回 [(receiver, 返回值)];receiver 必须有 **kwargs;sender 过滤;send() 遇异常直接抛出、send_robust() 捕获并继续;dispatch_uid 去重;一次 send 的开销 0.12–5.61 µs。

Django Signal 信号 真实验证 动画演示
Django 2026-09-30

pre_save、post_save 执行时机

用 execute_wrapper 记录 SQL,看 pre_save / post_save / pre_delete / post_delete 与 INSERT、UPDATE、DELETE 的交错顺序;update_fields 会传进信号;atomic 里 post_save 在 COMMIT 之前;queryset.update() 不发信号;pre_save 里改字段会写入。

Django Signal pre_save post_save 真实验证 动画演示
Django 2026-09-30

Signal 为什么可能重复注册

Signal 去重靠的是函数对象的身份:同一个函数 connect 两次只算一个,但工厂函数造的相同代码、被不同模块名导入两次的 @receiver、每次新建的 lambda 都会重复触发;dispatch_uid 让它们只留一个。

Django Signal 重复注册 dispatch_uid 真实验证 动画演示
Django 2026-09-30

Signal 与事务提交顺序

在自己起的 PostgreSQL 上验证:atomic 里 post_save 触发时另一个连接看不到数据,on_commit 时看得到;回滚后 post_save 里的副作用已经发生,on_commit 回调不执行;autocommit 时 post_save 已可见。

Django Signal 事务 on_commit PostgreSQL 真实验证 动画演示
Django 2026-09-30

Signal 是否适合处理复杂业务

把业务逻辑放进 post_save:一行 create() 悄悄变成 7 次查询;receiver 抛异常会让 create() 抛出、无事务时订单已写入;在信号里 save() 自己会 RecursionError;执行顺序就是 connect 顺序;改成显式服务函数则一目了然。

Django Signal 业务逻辑 真实验证 动画演示
Django 2026-09-30

自定义 Signal

自定义 Signal 的写法与边界(Django 6.1.1):providing_args 已移除;sender 按相等匹配,类、字符串、实例互不相通;send() 与 asend() 对同步/异步 receiver 的耗时;send_robust 把异常放进返回值。

Django Signal 自定义信号 async 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号