Django3.1偶发UndefinedError: 'request'未定义模板错误无法复现
问题根本原因
Django并不会默认向所有模板上下文注入request变量,你遇到的偶发现象本质是触发内置CSRF校验失败视图时渲染模板缺少request导致的,具体原因拆解如下:
- 首先,
request变量进入模板上下文的前提是你在TEMPLATES配置的上下文处理器中开启了django.template.context_processors.request,且渲染模板时使用的是RequestContext(正常业务视图调用render()方法时默认会用),所以正常访问页面不会触发报错。 - 从报错栈可以看到,错误出现在Django自带的
csrf_failure视图渲染自定义403_csrf.html模板的过程中:Django内置的错误类视图(包括CSRF失败、404、500等默认处理视图)构造模板上下文时不会加载全量自定义上下文处理器,也不会默认传入request对象,刚好你的全局基础模板base.html中引用了request.csp_nonce,因此只要触发CSRF失败就会抛出该错误,这也是你无法在正常访问流程复现的原因。 - 额外需要注意:你使用的
django-jinja模板引擎如果没有正确配置上下文处理器,也会放大该问题,但如果正常访问没有报错可以排除这个可能性。
排查解决步骤
- 第一步:确认基础配置
检查settings.py中的TEMPLATES配置项,确保你使用的模板引擎(django-jinja对应配置块)的上下文处理器列表中存在django.template.context_processors.request,示例配置参考:TEMPLATES = [ { "BACKEND": "django_jinja.backend.Jinja2", "OPTIONS": { "context_processors": [ "django.template.context_processors.request", # 其他你需要的上下文处理器 ], } }, # 其他模板引擎配置 ] - 第二步:修复内置错误视图的上下文缺失问题,二选一即可:
- 方案1:自定义CSRF失败处理视图,确保渲染时传入
request
自己实现一个CSRF失败视图,替换Django默认视图,示例代码:
然后在# yourapp/views.py from django.shortcuts import render def custom_csrf_failure(request, reason=""): return render(request, "403_csrf.html", {"reason": reason}, status=403)settings.py中添加配置:
如果你的404、500错误页面也继承了带CSRF_FAILURE_VIEW = "yourapp.views.custom_csrf_failure"request引用的基础模板,也需要同理自定义这两个错误视图。 - 方案2:修改模板代码兼容无
request的场景
在基础模板引用request的位置做兼容处理,避免变量不存在时抛出错误,示例写法:{# 写法1:加判断 #} {% if request %} <link nonce="{{ request.csp_nonce }}" rel="manifest" href="{{ static('manifest.json') }}"> {% endif %} {# 写法2:用default过滤器设置默认值 #} <link nonce="{{ request.csp_nonce|default('') }}" rel="manifest" href="{{ static('manifest.json') }}">
- 方案1:自定义CSRF失败处理视图,确保渲染时传入
- 第三步:手动复现验证修复效果
构造无CSRF token的POST请求触发CSRF校验失败,比如打开无痕浏览器,直接向你的POST接口提交表单,检查是否还会抛出request未定义的错误即可。
内容的提问来源于stack exchange,提问作者alias51
相关产品推荐
相关产品推荐

