知其然,知其所以然
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 真实验证 动画演示
Django 2026-09-30

Signal 的弱引用机制

Signal 默认对 receiver 用弱引用,但实测局部函数、lambda、partial 在函数返回并 gc 之后仍被调用——因为 connect 时的签名缓存 lru_cache(512) 强引用了它们,挤满缓存后才被回收;绑定方法则随对象销毁自动消失;weak=False 会拖住对象。

Django Signal weakref 内存 真实验证 动画演示
Django 2026-09-30

Signal 与 Bulk 操作的关系

bulk_create / bulk_update / queryset.update() 都不发 pre_save / post_save;queryset.delete() 在没有 delete 信号时是快速删除(2000 行 3 条 SQL),挂上 post_delete 后要取出对象逐个发信号(23 条 SQL);删 2 万行 0.6 ms → 125.9 ms。

Django Signal bulk_create delete 真实验证 动画演示
Django 2026-09-30

Django 异步 View

20 个并发请求、每个视图等 0.5 s:uvicorn(ASGI)下 async 与 sync 视图都是约 513 ms;gunicorn 同步 worker(WSGI)下无论 async 还是 sync 都是约 10.1 s。async def 视图要放在 ASGI 服务器上才有并发收益。

Django 异步 ASGI uvicorn gunicorn 真实验证 动画演示
Django 2026-09-30

ASGI 下的同步与异步代码

用线程名和 get_running_loop() 看视图代码到底跑在哪:ASGI 下 async 视图在主线程的事件循环里,sync 视图在每个请求独立的工作线程里;WSGI 下 sync 视图在 worker 主线程,async 视图在一个临时事件循环里。

Django ASGI WSGI 事件循环 线程 真实验证 动画演示
Django 2026-09-30

sync_to_async 的线程行为

sync_to_async 的线程行为:默认 thread_sensitive=True 时同一请求里全部同步代码共用一个线程(10 个 0.2 s 任务 2037 ms);thread_sensitive=False 用线程池(206 ms、10 个线程,50 个任务只用到 14 个线程);不同请求互不影响。

Django asgiref sync_to_async 线程 真实验证 动画演示
Django 2026-09-30

SynchronousOnlyOperation 产生原因

在 async 上下文里直接调用同步 ORM(count、遍历、create、cursor)全部抛 SynchronousOnlyOperation;用 a 前缀方法、async for 或 sync_to_async 才可以;DJANGO_ALLOW_ASYNC_UNSAFE=true 只是关掉检查;真实 uvicorn 服务里表现为 500。

Django 异步 SynchronousOnlyOperation ORM 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号