Django中404页面为何不执行中间件(Middleware)处理?
问题描述
我在URL配置中设置了如下路径:
path( "kitten/", views.Kitten.as_view(), name="kitten", ),
同时将不存在URL的处理器指向同一个视图:
handler404 = views.Kitten.as_view()
我编写了一个用于设置上下文数据的中间件:
class CookieConsentMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): return self.get_response(request) def process_template_response(self, request, response): response.context_data["hasCookie"] = False return response
视图的实现非常简单:
class Kitten(TemplateView): template_name = "kitten.html"
模板会输出hasCookie的值。
访问kitten/时能正确显示hasCookie的值,但访问不存在的URL时,虽然加载了正确的模板,却没有显示hasCookie的值。
通过在中间件中添加调试语句发现,访问kitten/时process_view、process_template_response和process_exception都会被调用,但访问不存在的URL时这些方法都未被调用,仅在应用启动时调用了__init__。
为何URL配置中不存在的URL不会触发中间件调用?
原因分析与解决方案
核心原因
Django处理404错误的流程和正常URL匹配流程存在差异:
- 正常URL匹配成功时,请求会完整经过中间件链路,包括执行
__call__方法,以及后续的process_view、process_template_response等钩子函数。 - 当URL匹配失败触发
handler404时,Django是直接调用该处理器视图,并未走中间件的视图处理阶段——仅会执行中间件的__call__方法,但此时还未进入视图的模板响应流程,所以process_template_response这类钩子不会被触发,自然无法给上下文添加hasCookie数据。
解决方案
有两种实用的解决方式:
修改中间件,在
__call__阶段统一处理
如果需要给所有响应(包括404)添加上下文数据,可以在中间件的__call__方法中,获取响应后判断是否为模板响应,再补充数据:class CookieConsentMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request): response = self.get_response(request) # 检查是否是带上下文的模板响应 if hasattr(response, 'context_data'): response.context_data["hasCookie"] = False return response这种方式能覆盖正常请求和404请求的所有模板响应场景。
在视图中手动添加上下文数据
若仅需给目标视图(含404触发的情况)添加数据,可以重写视图的get_context_data方法:class Kitten(TemplateView): template_name = "kitten.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["hasCookie"] = False return context这样不管是正常访问还是404触发,视图都会主动注入上下文数据,无需依赖中间件钩子。
内容的提问来源于stack exchange,提问作者David McKee
相关产品推荐
相关产品推荐

