DRF-RequestsAndResponses

Request objects

DRF提供了Request请求来扩展Django通用的HttpRequest,并且提供了更为灵活的请求解析。

Request parsing

DRF框架使用中间件实现了将客户端发过来的请求从Django的HttpRequest解析成了DRF的Request,所以我们一般只需要了解如何使用这个Request.

.data

Request类的核心功能是request.data属性,与request.POST类似,但更适用于Web APIs

request.POST  # Only handles form data.  Only works for 'POST' method.
request.data  # Handles arbitrary data.  Works for 'POST', 'PUT' and 'PATCH' methods.

.query_params

request.query_params与Django自带的request.GET类似。

为了在代码中清晰起见, 我们建议使用request.query_params来代替 Django 的标准request.GET

.parsers

APIView类或者@api_view装饰器会确保这个属性会被自动设置成Parser实例的列表。当然,这个实例的列表取决于view的parser_classes或者配置文件settings.py中的DEFAULT_PARSER_CLASSES设置。

Note: 如果客户端发送了错误格式的内容,访问request.data可能会抛出ParseError异常。默认的APIView类或@api_view装饰器会捕获这个异常,然后返回400 Bad Request

Context negotiation

Request公开了一些属性来允许我们决定内容协商阶段的结果。

.accepted_renderer

内容协商阶段选择的渲染器实例

.accepted_media_type

一个字符串, 表示内容协商阶段接受的媒体类型

Authentication

DRF框架提供了灵活的、面向每个请求的的认证,使我们能够:

  • 对 API 的不同部分使用不同的身份验证策略;

  • 支持使用多个身份验证策略;

  • 提供与传入请求关联的用户和令牌信息。

.user

request.user通常返回django.contrib.auth.models.User的一个实例, 当然,这取决于使用的认证策略。

如果请求未经验证,那么,request.user默认是django.contrib.auth.models.AnonymousUser的一个实例。

.auth

request.auth返回任何额外的身份验证上下文信息。 request.auth的确切行为取决于所使用的身份验证策略, 但它通常可能是对请求进行身份验证的令牌的实例。

如果请求未经身份验证, 或者不存在其他上下文, 则request.auth的默认值为 None

.authenticators

APIView类或者@api_view装饰器会确保这个属性会被自动设置成Authentication实例的列表。当然,这个实例的列表取决于view的pauthentication_classes或者配置文件settings.py中的DEFAULT_AUTHENTICATORS设置。

Browser enhancements

DRF框架支持一些浏览器增强功能, 如基于浏览器的 putpatchdelete 表单。

.method

request.method 返回请求HTTP方法的大写字符串。

明确地支持基于浏览器的 putpatchdelete 表单方法。

.content_type

request.content_type,返回表达HTTP请求Body媒体类型的字符串对象。没有提供媒体类型的话,则返回空字符串。

通常不需要直接访问请求的内容类型, 因为其一般依赖于DRF框架的默认请求分析行为。

如果我们确实需要访问请求的内容类型, 则应优先使用request.content_type而不是request.META.get('HTTP_CONTENT_TYPE'), 因为它为器的非表单内容提供透明的支持。

.stream

request.stream返回表示请求正文内容的流。

Response objects

DRF同样提供了Response,继承自Django的SimpleTemplateResponse

return Response(data)

来看看其部分源码:

class Response(SimpleTemplateResponse):
    """
    An HttpResponse that allows its data to be rendered into
    arbitrary media types.
    """

    def __init__(self, data=None, status=None,
                 template_name=None, headers=None,
                 exception=False, content_type=None):
        """
        Alters the init arguments slightly.
        For example, drop 'template_name', and instead use 'data'.

        Setting 'renderer' and 'media_type' will typically be deferred,
        For example being set automatically by the `APIView`.
        """
        super(Response, self).__init__(None, status=status)

        if isinstance(data, Serializer):
            msg = (
                'You passed a Serializer instance as data, but '
                'probably meant to pass serialized `.data` or '
                '`.error`. representation.'
            )
            raise AssertionError(msg)

        self.data = data
        self.template_name = template_name
        self.exception = exception
        self.content_type = content_type

        if headers:
            for name, value in six.iteritems(headers):
                self[name] = value

可以看到构造返回的Reponsse时,可指定:

  • data: 具体返回的数据;
  • status: 返回的状态,具体对应DRF status模块的状态码,默认返回200;
  • template_name:如果选择了HTMLRenderer,则可用此参数指定模板名;
  • headers: Http headers 字典;
  • content_type:response的内容类型。

Attributes

.data

response的未渲染的序列化数据。

.status_code

HTTP response的数字状态码.

.content

response渲染后的内容。.render()方法必须先调用,然后才能访问.content.

.template_name

模板名称 (如果提供)。仅在response接受的渲染器是 HTMLRenderer 或其他一些自定义模板渲染器时才需要。

.accepted_renderer

将被用来渲染response的渲染器实例。

APIView@api_view 在从view返回response之前自动设置.

.accepted_media_type

内容协商阶段选择的媒体类型.

APIView@api_view 在从view返回response之前自动设置.

.renderer_context

就要传递给渲染器的.render()方法的额外上下文信息字典。

APIView@api_view 在从view返回response之前自动设置.

Standard HttpResponse attributes

Response,继承自SimpleTemplateResponse,所有常用的属性和方法也可在response上使用。例如, 您可以以标准方式在响应上设置标头:

response = Response()
response['Cache-Control'] = 'no-cache'

.render()

TemplateResponse一样,这个方法用于将response序列化的数据渲染成最后的responsse context。当.render被调用时,实际上会去调用accepted_renderer上的render(data, accepted_media_type, renderer_context)``response context方法。

Pulling it all together

让我们再用之前章节基于函数的视图的例子来看看requestresponse的使用:

@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)

上面的例子中,reques.data 可以处理传入的 json 请求, 当然也可以处理其他格式的请求。同时返回的结果也不再需要JSONResponse来转换成json格式。

最后让我们调用接口,来看看返回的结果是怎么样的?

# 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"
}
Copyright © itrunner.cn 2020 all right reserved,powered by Gitbook该文章修订时间: 2022-08-28 07:44:16

results matching ""

    No results matching ""