DRF 的 Response 与 Django 的 JsonResponse:揭秘常用工具的本质

与大多数 Django 开发者一样,我在 [[Django]] 项目中几乎 99% 的情况下都会搭配使用 DRF ([[Django REST Framework]]) 包。因此,在向服务器返回响应时,无论是 API 响应还是模板请求的简单 JSON 响应,我都会不假思索地使用 Response 这个结构化的响应类。真的是“随手即用”,毫无顾虑。

原因很简单,它不仅与序列化器(Serializer)配合得天衣无缝,而且在所有响应中默认使用 Response 类,省去了我思考和抉择的烦恼。

然而,今天我突然萌生了一个疑问:“既然如此,DRF 的 Response 和 django.http.JsonResponse 到底有什么区别?它们的不同之处又在哪里?” 今天,我将尝试解答这个疑问。


1. 根源不同:是静态(Static)还是灵活(Flexible)?

JsonResponse와 Response의 차이 도식화

首先,我们来看看两者的“出身”,发现了一些有趣的差异。

  • JsonResponse:继承自 Django 的 HttpResponse。它的目的非常明确:“接收数据,通过 json.dumps() 进行序列化,然后将 Content-Type 设置为 application/json 并发送出去。” 仅此而已。它是一个非常简单直观的工具。

  • DRF Response:它继承自 SimpleTemplateResponse。咦?这是什么情况?为什么会继承一个与模板相关的类呢?从这里开始,Response 的真实面目逐渐浮现。原来,我一直“随手”使用的这个工具,是一个尚未确定最终呈现形式的“渲染前数据容器”


2. 核心区别:内容协商 (Content Negotiation)

JsonResponse 就像一个“非 JSON 不可”的固执家伙,而 DRF 的 Response 则非常灵活和智能。

DRF 的 Response 会询问客户端想要什么。(这被称为 内容协商 Content Negotiation)。如果客户端在请求头中发送 Accept: text/html,它就会展示我们熟悉的漂亮“可浏览 API”界面;如果发送 Accept: application/json,它则只会返回纯粹的 JSON 数据。

也就是说,Response 类本身只负责承载数据,而实际以何种形式呈现,则由 DRF 的 渲染器(Renderer) 来决定。我们之所以能“随手”使用 Response 就能得到恰当的响应,正是因为 DRF 在背后努力进行了协商。

这真是一个令人惊叹的发现和领悟。我不得不感叹,这工具设计得多么精妙。每当此时,我都会对 Django/DRF 的开发者和贡献者们心生几秒的感激。


3. 序列化(Serialization)的便捷性

使用 JsonResponse 时,我们需要手动将数据“整理”成 Python 字典或列表形式再传递。而 Response 则与 DRF 的序列化器(Serializer)是绝配。

我们来看一个简单的例子。如果需要返回博客文章信息,会是怎样的情况呢?

情况 A: JsonResponse (手动繁琐版)

from django.http import JsonResponse
def post_detail(request, pk):
    post = Post.objects.get(pk=pk)
    # 需要手动将数据逐一构建成字典。
    # 如果有 20 个字段呢?嗯... 可能会让人抓狂。
    data = {
        "title": post.title,
        "content": post.content,
        "created_at": post.created_at.strftime("%Y-%m-%d"), # 日期格式也需手动处理!
    }
    return JsonResponse(data)

情况 B: DRF Response (自动化版本)

from rest_framework.response import Response
from rest_framework.decorators import api_view

@api_view(['GET'])
def post_detail(request, pk):
    post = Post.objects.get(pk=pk)
    serializer = PostSerializer(post)

    # 直接返回 .data 即可。
    # 复杂的关联(外键)或日期格式化都由序列化器自动处理。
    return Response(serializer.data)

看到了吗?JsonResponse 需要我们亲手处理食材并摆盘,而 Response 则可以将复杂的模型实例或查询集放入序列化器这个“自动烹饪机”中,然后直接返回其结果。渲染器会负责将其优雅地转换成最终的 JSON 字符串。

有时在与像 ChatGPT 这样“细致入微”的 AI 协作时,我曾几次发现它过度“热情”或“防御性”地手动构建响应数据,最终才调用 Response 返回。对于注重效率的开发者来说,看到这样的代码可能会感到不适。现在,如果 AI 再生成这样的代码,我们可以果断地进行修正。


那么,即使是简单的 JSON 响应,我们也能继续使用 Response 吗?

这 100% 是基于我个人主观经验得出的结论,但至少我的答案是:“完全没问题,甚至值得推荐。”

当然,从技术上讲,Response 会经过内容协商(Content Negotiation)过程并检查多个渲染器,因此相比 JsonResponse 可能会有极其微小的额外计算开销。然而,在现代基础设施中(甚至在我运行的 Raspberry Pi 5 上!),这种差异几乎是无法感知的。

相反,持续使用 Response 所带来的优势要大得多。

  1. 一致性: 可以在整个项目中统一响应格式。
  2. 调试: 通过浏览器访问时,可以方便地通过可浏览 API (Browsable API) 直接查看数据。
  3. 灵活性: 即使将来需要将响应格式扩展到 XML 或 YAML,也只需修改配置,无需改动代码。

总结:知其所以然,豁然开朗

通过今天的学习,我得出了这样的结论:

“归根结底,两者并没有显著的性能差异,在 DRF 环境下,继续沿用 Response 对身心健康更有益。”

然而,了解我每天使用的工具内部如何运作,以及为什么必须使用 Response 而不是 JsonResponse 这个独立类,这种“知其所以然”的感觉让我心情非常舒畅。果然,开发者只有不断追问“为什么”,才能更进一步。现在,既然已经揭示了其本质,我将更自信地使用 Response


如果你也曾因 Django 和 DRF 之间这些微妙的差异而辗转反侧,希望这篇文章能为你带来帮助。

有任何疑问或想法,欢迎在评论区留言!

如果觉得这篇文章有价值,请关注我!您可以在 Mikihands Blog Flatform 注册账号后进行关注。在博客上撰写文章并被他人阅读的体验……相当有趣。