媒体文件上线:DEBUG=False 时 static() 返回空路由、/media/ 是 404;FileField 把 ../../evil.txt 保存成 docs/evil.txt、重名加随机后缀;2.5 MiB 以上用临时文件;DATA_UPLOAD_MAX_MEMORY_SIZE 不限文件,文件个数默认最多 100;上传的 .html 会以 text/html 返回。
连接池:默认 CONN_MAX_AGE=0 每个请求新建数据库连接(200/200 次,中位 2.60 ms),持久连接与连接池都不再新建(0.52 / 0.51 ms);max_connections=20 时 40 线程持久连接有 20 个请求被拒,连接池全部成功。
生产环境日志:没有 LOGGING 配置、DEBUG=False 时,gunicorn 日志里只有 1 行,500 的 traceback、404、DisallowedHost 都不见了;配置 LOGGING 后有 35 行、3 段 traceback;请求 ID 过滤器让一次请求的日志可以按 id 查;got_request_exception 信号是错误追踪的挂钩。
健康检查:探针用 Pod IP 当 Host 走 http 会被 ALLOWED_HOSTS 拒(400)或被 SSL 重定向(301);放在 MIDDLEWARE 最前面的存活中间件绕开这些、0 次数据库查询;就绪探针查数据库,数据库停掉后 503 而存活仍是 200;connect_timeout=2 使不可达的数据库约 2 s 后返回 503。
在一个带打点的真实 Django 项目里,按时间顺序记录 manage.py check 与一次请求中各模块被导入、被调用的次序:settings → apps.py → models → ready() → urls / views / 中间件;并量了 django.setup() 的耗时(103→129 ms)。
实测 Django settings:import settings 时不加载、首次读取才导入;缺环境变量与写错模块名是两种不同的错误;只有全大写名字算设置(默认项 150 个);override_settings 对导入时读取过的值无效;configure() 只能调用一次。
实测 Django 应用注册表:apps_ready / models_ready / ready 三个标志在 models 导入时与 ready() 里各是什么值;setup() 前使用会怎样;重复 label、不存在的 app 的报错原文;AppConfig 自动发现遇到多个子类且都没标 default 时会悄悄退回基类。
实测 AppConfig.ready():按 INSTALLED_APPS 顺序调用、调用时所有模型已加载;所有 manage.py 命令都会触发;runserver 默认自动重载会调用 2 次(来自 2 个进程);在 ready() 里查还不存在的表会让 migrate 自己失败。
实测 Django URL Resolver:第一个匹配的模式胜出、转换器的边界、include() 的命名空间;APPEND_SLASH 下 POST 无斜杠在 DEBUG=False 时静默 301 丢体;匹配是线性扫描(N=5000 时匹配最后一个 712 µs)。
实测 reverse():args / kwargs / 字符串参数的行为与 NoReverseMatch 的报错原文;自定义转换器的 to_url;同名同参数时后定义的胜出;命名空间;第一次调用要建反向字典(N=5000 时 140 ms),之后每次约 7.8 µs。
用三层带日志的中间件实测:正常请求的进入/返回顺序、某层短路后内层与视图不执行、视图或中间件抛异常时每一层看到的是 500 响应而不是异常(DEBUG 只改变响应正文)。
用日志实测 process_view、process_exception、process_template_response 三个中间件钩子的调用位置与顺序:process_view 按声明顺序、后两者反向;process_view 返回响应会跳过视图;process_exception 第一个返回响应的会终止链;TemplateResponse 在所有钩子之后才渲染。