跳至主要內容

Rest-framework专栏讲解(五):Request

Mr.暴走の海鸽约 2049 字大约 7 分钟

Rest-framework专栏讲解(五):Request

目录


点击跳转到 Rest-Framework 专栏目录open in new window

官方原文链接open in new window

框架的 request 给予了很标准的属性, 并拓展了标准 HTTPRequest 对象, 比如更加灵活的请求解析(request parsing)和认证(request authentication),你会在开发中很方便的使用它。

🐍如果你正在开发基于 REST 的 web API 服务...... 应该忽略 request.POST。 — Malcom Tredinnick,Django 开发组

Request 解析open in new window

REST framwork 的 Request 对象提供了灵活的请求解析,允许你使用 JSON data 其他 media types 像通常处理表单数据一样处理请求。

.data

request.data 中你可以很方便的获取客户端传递给你的 json 数据或者表单提交, 不需要像 request.POST.get() 一样很麻烦的操作, 并且能解析文件传输,这跟标准的 request.POSTrequest.FILES 类似,并且还具有以下特点:

  • 包括所有解析的内容,文件(file) 和 非文件(non-file inputs)。
  • 支持解析 POST 以外的 HTTP method , 比如 PUTPATCH
  • 更加灵活,不仅仅支持表单数据,传入同样的 JSON 数据一样可以正确解析,并且不用做额外的处理(意思是前端不管提交的是表单数据,还是 JSON 数据,.data 都能够正确解析)。
def update(self, request, *args, **kwargs):
    if request.data.get('params') == True:
        ...

.query_params

GET 请求中, query_params 的命名方式才更加凸显传参的方式, 当然, request.query_params.get('params')request.GET.get('params') 是等价的。

为了代码更加清晰可读,推荐使用 request.query_params ,而不是 Django 中的 request.GET,这样那够让你的代码更加明显的体现出 ----- 任何 HTTP method 类型都可能包含查询参数(query parameters),而不仅仅只是 'GET' 请求。

.parsersopen in new window

APIView 类或者 @api_view 装饰器将根据视图上设置的 parser_classessettings 文件中的 DEFAULT_PARSER_CLASSES 设置来确保此属性(.parsers)自动设置为 Parser 实例列表。

通常不需要关注该属性......

如果你非要看看它里面是什么,可以打印出来看看,大概长这样:

[<rest_framework.parsers.JSONParser object at 0x7fa850202d68>, <rest_framework.parsers.FormParser object at 0x7fa850202be0>, <rest_framework.parsers.MultiPartParser object at 0x7fa850202860>]

恩,包含三个解析器 JSONParserFormParserMultiPartParser

注意: 如果客户端发送格式错误的内容,则访问 request.data 可能会引发 ParseError 。默认情况下, REST framework 的 APIView 类或者 @api_view 装饰器将捕获错误并返回 400 Bad Request 响应。 如果客户端发送的请求内容无法解析(不同于格式错误),则会引发 UnsupportedMediaType 异常,默认情况下会被捕获并返回 415 Unsupported Media Type 响应。

内容协商open in new window

该请求公开了一些属性,允许你确定内容协商阶段的结果。这使你可以实施一些行为,例如为不同媒体类型选择不同的序列化方案。

.accepted_rendereropen in new window

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

.accepted_media_typeopen in new window

表示内容协商阶段接受的 media type 的字符串。

认证(Authentication)open in new window

REST framework 提供了灵活的认证方式:

  • 可以在 API 的不同部分使用不同的认证策略。
  • 支持同时使用多个身份验证策略。
  • 提供与传入请求关联的用户(user)和令牌(token)信息。

.user

request.user 通常会返回 django.contrib.auth.models.User 的一个实例,但其行为取决于正在使用的身份验证策略。

在你已认证的情况下, 访问该属性得到的是你用户模型的一个实例对象, 你可以通过 request.user.id 的方式获取用户 ID 属性, 但在未验证, 或者未通过验证的情况下该属性返回的是 django.contrib.auth.models.AnonymousUser 的一个实例对象。

.auth

request.auth 返回任何附加的认证上下文(authentication context)。request.auth 的确切行为取决于正在使用的身份验证策略,但它通常可能是请求经过身份验证的令牌(token)实例。

如果请求未经身份验证,或者没有附加上下文(context),则 request.auth 的默认值为 None

.authenticatorsopen in new window

APIView 类或 @api_view 装饰器将确保根据视图上设置的 authentication_classes 或基于 settings 文件中的 DEFAULT_AUTHENTICATORS 设置将此属性(.authenticators)自动设置为 Authentication 实例列表。

**通常不需要关注该属性...... **

注意:调用 .user.auth 属性时可能会引发 WrappedAttributeError 异常。这些错误源于 authenticator 作为一个标准的 AttributeError ,为了防止它们被外部属性访问修改,有必要重新提升为不同的异常类型。Python 无法识别来自 authenticator 的 AttributeError,并会立即假定请求对象没有 .user.auth 属性。authenticator 需要修复。

多说几句

.authenticators 其实存的就是当前使用的认证器(authenticator)列表,打印出来大概是这样:

[<rest_framework.authentication.SessionAuthentication object at 0x7f8ae4528710>, <rest_framework.authentication.BasicAuthentication object at 0x7f8ae45286d8>]

可以看到这里使用的认证器(authenticator)包括 SessionAuthenticationBasicAuthentication

浏览器增强open in new window

REST framework 支持基于浏览器的 PUTPATCHDELETE 表单。

.method

该属性能返回请求方式的大写字符串, 如 GET

request.method 返回请求 HTTP 方法的大写字符串表示形式。如 GET,POST...。

透明地支持基于浏览器的 PUTPATCHDELETE 表单。

在请求中, 如果不需要重写框架的方法, 或者实现自定义返回数据、校验等, 这些属性一般是不会被使用到的。

.content_typeopen in new window

request.content_type 返回表示 HTTP 请求正文的媒体类型(media type)的字符串对象(比如: text/plain , text/html 等),如果没有提供媒体类型,则返回空字符串。

通常不需要直接访问此属性,一般都依赖与 REST 框架的默认请求解析行为。

不建议使用 request.META.get('HTTP_CONTENT_TYPE') 来获取 content type 。

更多相关信息以后再说~

.streamopen in new window

request.stream 返回一个代表请求主体内容的流。

通常不需要直接访问此属性,一般都依赖与 REST 框架的默认请求解析行为。

标准的 HttpRequest 属性open in new window

由于 REST framework 的 Request 扩展于 Django 的 HttpRequest,所有其他标准属性和方法也可用。例如request.METArequest.session 字典都可以正常使用。

请注意,由于实现原因,Request 类不会从 HttpRequest 类继承,而是使用组合扩展类(优先使用组合,而非继承,恩,老铁没毛病 0.0)