Django返回HttpResponseNotFound报错:context must be a dict rather than type
Django权限控制问题:跨公司Item访问未返回404反而触发500错误
我正在开发一个Django项目,其中有一个名为Item的资源。需求是用户仅能查看同公司的Item详情,否则返回404。我编写了如下代码:
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # To only show items in your company if (context['item'].company != getCompany(self.request.user)): return HttpResponseNotFound return context
getCompany是我自定义的函数,用于获取用户所属公司,该函数已在其他功能中验证可用。但访问其他公司的Item详情时,未返回预期的404,反而触发内部服务器错误,报错信息为:
Internal Server Error: /fr/items/5/ Traceback (most recent call last): File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/core/handlers/exception.py", line 55, in inner response = get_response(request) File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/core/handlers/base.py", line 220, in _get_response response = response.render() File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/template/response.py", line 114, in render self.content = self.rendered_content File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/template/response.py", line 92, in rendered_content return template.render(context, self._request) File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/template/backends/django.py", line 58, in render context = make_context( File "/Users/username/Documents/Work/Inventory/inventory-env/lib/python3.9/site-packages/django/template/context.py", line 278, in make_context raise TypeError( TypeError: context must be a dict rather than type.
问题原因与解决方案
核心问题
get_context_data方法的职责是返回字典类型的模板上下文,但你直接返回了HttpResponseNotFound类(而非实例),后续模板渲染流程会把这个类当作上下文字典处理,最终触发TypeError。此外,在get_context_data中处理权限校验并返回响应,本身就不符合Django视图的设计逻辑。
正确实现方式
应该在视图获取对象的入口方法get_object中做权限校验,不符合条件则抛出Http404异常,Django会自动将其转换为404响应:
from django.http import Http404 def get_object(self, queryset=None): obj = super().get_object(queryset=queryset) # 校验用户所属公司与Item公司是否一致 if obj.company != getCompany(self.request.user): raise Http404("你无权访问该资源") return obj
原有的get_context_data方法如果没有额外的上下文处理逻辑,可以直接删除,由父类方法默认处理;如果有其他逻辑,保留正常返回上下文即可:
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 其他上下文构建逻辑(如需要) return context
为什么这样更合理
get_object是DetailView等视图获取数据对象的标准入口,在这里做权限校验符合Django视图的执行流程。- 抛出
Http404异常是Django处理资源不可访问的标准方式,能自动生成规范的404响应。 - 分离了权限校验与上下文构建的职责,代码逻辑更清晰、易维护。
内容的提问来源于stack exchange,提问作者whoami0605
相关产品推荐
相关产品推荐

