DRF - 2.Requests and Responses

本文是我对DRF官网的翻译,并做一些学习笔记。翻译的不是很好,如果有看不懂的建议可以先看看原文,欢迎指正。

原文:2 - Requests and Responses- Django REST framework

从现在开始我们要准备开始接触REST框架的核心部分了。让我们介绍几个基本的构建块。

请求对象Request objects

REST框架引入的Request对象是对常规DjangoHttpRequest对象的扩展,也提供了更灵活的请求解析。Resquest对象的核心功能request.data属性,它和reqeust.POST很像,但是对于WebAPI来说更有用。

request.POST  # 只处理表单数据,只对POST方法有用
request.data  # 处理任意数据,对POST、PUT、PATCH都有用

响应对象Response objects

REST框架还引入了Response对象,它是一种TemplateResponse类型,它接受未渲染的内容并使用协商来确定正确的内容类型以返回给客户端。

return Response(data)  # Renders to content type as requested by the client.

状态码

在视图中使用数字 HTTP 状态代码并不总能一目了然,而且如果得到错误代码,很容易忽视。 REST框架为每个状态代码提供了更明确的标识符,例如状态模块中的HTTP_400_BAD_REQUEST。最好使用这些而不是使用数字标识符。

包装API视图

REST框架提供了两个装饰器,用来写API视图。

  1. @api_view装饰器,用来处理基于函数的视图
  2. APIView类,用来处理基于类的视图

这些包装提供了一些功能,例如确保您在视图中接收到Request实例,然后向Response对象中添加上下文,以便可以执行内容协商。
这些包装也提供了返回405 Method Not Allowed响应的行为,然后在收到request.data异常数据时处理ParseError异常。

把它们组装起来

好了,现在我们开始用这些新的组件来重构视图。

from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer


@api_view(['GET', 'POST'])
def snippet_list(request):
    """
    List all code snippets, or create a new snippet.
    """
    if request.method == 'GET':
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = SnippetSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

这对于先前的例子来说,有了一些提升。这更清晰一些,也和Django的Forms API更为类似。这里也使用了具名状态码,让返回值的意义更明确。
以下是views.py模块中单个snippet的视图。

@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a code snippet.
    """
    try:
        snippet = Snippet.objects.get(pk=pk)
    except Snippet.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    elif request.method == 'PUT':
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

这应该很熟悉,和常规的Django视图差别不大。
我们不再显式地将请求或响应绑定到给定的内容类型。request.data可以处理即将到来的json请求,也可以处理其他的格式。类似的,响应对象也会被REST框架渲染成正确的格式。

向URL添加可选的格式后缀

响应不再和单一的内容类型绑定,为了发挥出这个优势,我们为API端点添加对格式后缀的支持。使用格式后缀让URL明确地指向给定的格式,这意味着我们的API可以处理像http://example.com/api/items/4.json这样的URL。
给我们的两个视图加上fomat参数,像这样:

def snippet_list(request, format=None):

def snippet_detail(request, pk, format=None):

现在更新snippets/urls.py文件,向已有的URL添加一些额外的format_suffix_patterns

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    path('snippets/', views.snippet_list),
    path('snippets/<int:pk>', views.snippet_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

没有必要把这些额外的URL样式添加进来,不过这为特定的格式提供了一个简单、明了的方式。

现在看起来如何

tutorial part 1一样,继续在命令行里测试。虽然我们提供了更好的错误处理非法请求的方式,但一切都非常相似。
我们可以像之前一样,得到一个所有代码片段的列表。

http http://127.0.0.1:8000/snippets/

HTTP/1.1 200 OK
...
[
  {
    "id": 1,
    "title": "",
    "code": "foo = \"bar\"\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  },
  {
    "id": 2,
    "title": "",
    "code": "print(\"hello, world\")\n",
    "linenos": false,
    "language": "python",
    "style": "friendly"
  }
]

可以通过Accept标头来控制返回的响应格式:

http http://127.0.0.1:8000/snippets/ Accept:application/json  # Request JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html         # Request HTML

或者用特定的格式后缀:

http http://127.0.0.1:8000/snippets.json  # JSON suffix
http http://127.0.0.1:8000/snippets.api   # browsable API suffix

相似的,我们可以用Content-Type来控制请求的格式。

# POST using form data
http --form POST http://127.0.0.1:8000/snippets/ code="print(123)"

{
  "id": 3,
  "title": "",
  "code": "print(123)",
  "linenos": false,
  "language": "python",
  "style": "friendly"
}

# POST using JSON
http --json POST http://127.0.0.1:8000/snippets/ code="print(456)"

{
    "id": 4,
    "title": "",
    "code": "print(456)",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

如果对上面的http加了--debug参数,那么就能看到请求头里的请求类型了。
现在打开浏览器,浏览一下http:/127.0.0.1:8000/snippets/吧。

可浏览性

由于API会根据客户端请求选择响应的内容类型,因此认情况下,当 Web 浏览器请求该资源时,它将返回资源的 HTML 格式表示。这允许 API 返回一个完全可通过 Web 浏览的 HTML 表示。
拥有一个可浏览网页的 API 好处非常多,并使开发和使用你的 API 变得更加容易。它还显著降低了其他想要检查和使用您的 API 的开发人员的进入门槛。
有关可浏览 API 功能以及如何自定义它的更多信息,请参阅可浏览browsable api

下一步是什么?

tutorial part 3,我们会开始使用基于类的视图,然后看看通用视图是如何减少我们的代码量的。

相关文章

显卡天梯图2024最新版,显卡是电脑进行图形处理的重要设备,...
初始化电脑时出现问题怎么办,可以使用win系统的安装介质,连...
todesk远程开机怎么设置,两台电脑要在同一局域网内,然后需...
油猴谷歌插件怎么安装,可以通过谷歌应用商店进行安装,需要...
虚拟内存这个名词想必很多人都听说过,我们在使用电脑的时候...