您的位置:首页 > 编程语言 > Go语言

Django Rest Framework:进一步理解序列化之基于函数的视图

2020-08-23 10:17 1016 查看

一,请求对象Request

REST framework 引入了一个扩展自常规 HttpRequest 对象的

Request 对象
,增加了对 REST framework 灵活的请求解析和请求认证的支持。
Request 对象的核心功能是
request.data 属性
,它与 request.POST 类似,但对于使用 Web API 更加有用。

  • request.POST 只处理表单数据。 只适用于 ‘POST’ 方法。
  • request.data 处理任意数据。 适用于 ‘POST’,‘PUT’ 和 ‘PATCH’ 方法。

1,请求解析

REST框架的请求对象提供了灵活的请求解析,允许以与通常处理表单数据相同的方式处理JSON数据或其他媒体类型的请求。
1,.data:

request.data
返回请求体的解析后的内容。这与标准的 request.POST 和 request.FILES 属性类似,但也有不同:

  • 它包括所有解析的内容,包括文件和非文件输入。
  • 它支持解析 POST 以外的 HTTP 方法的内容,这意味着可以访问 PUT 和 PATCH 请求的内容。
  • 它支持 REST framework 的灵活请求解析,而不仅仅是支持表单数据。例如,处理传入的JSON数据的方式与处理传入的表单数据的方式相同。
  • 更过详情请参考官方API:解析器

2,.query_params:
request.query_params 是 request.GET 更正确的命名同义词。
为了使代码内部更清晰,官方推荐使用 request.query_params 而不是 Django 的标准request.GET。这样做有助于让代码库更加正确和明显 —— 任何 HTTP 方法类型都可能包含查询参数,而不仅仅是 GET 请求。
3,.parsers:
APIView类或@api_view装饰器将确保根据视图上设置的解析器类或默认的解析器类设置,自动将该属性设置为解析器实例列表。

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

2,内容协商 (Content negotiation)

请求公开了一些属性,允许您确定内容协商阶段的结果。这允许实现一些行为,比如为不同的媒体类型选择不同的序列化方案。
1,

.accepted_renderer

渲染器实例是由内容协商阶段选择的。
2,.accepted_media_type:
表示内容协商阶段接受的媒体类型的字符串。

3,认证 (Authentication)

REST框架提供灵活的每请求身份验证,这使的能够:

  • 对API的不同部分使用不同的身份验证策略。
  • 支持使用多种身份验证策略。
  • 提供与传入请求相关联的用户和令牌信息。
    1,.user:
    request.user 通常会返回 django.contrib.auth.models.User 的一个实例,但其行为取决于正在使用的身份验证策略。
  • 如果请求未经身份验证,则request.user的默认值是django.contrib.auth.models.AnonymousUser的实例。更过详情请参考官方API:认证
    2,.auth:
    request.auth 返回任何附加的认证上下文。request.auth 的确切行为取决于正在使用的身份验证策略,但它通常可能是请求通过身份验证的令牌实例。
  • 如果请求未经身份验证,或者没有附加上下文,则 request.auth 的默认值为 None。
    3,.authenticators:
    APIView 类或 @api_view 装饰器将根据视图上设置的 authentication_classes 或根据 DEFAULT_AUTHENTICATORS 设置确保将此属性自动设置为 Authentication 实例列表。

4,浏览器增强

REST framework 支持一些浏览器增强功能,例如基于浏览器的 PUT,PATCH 和 DELETE 表单。
1,.method:
request.method 返回大写字符串表示的请求 HTTP 方法。

2,.content_type:
request.content_type 返回表示 HTTP 请求正文的媒体类型的字符串对象,如果没有提供媒体类型,则返回空字符串。

  • 如果需要访问请求的内容类型,则应该优先使用 .content_type 属性,而不是使用 request.META.get(‘HTTP_CONTENT_TYPE’),因为它为基于浏览器的非表单内容提供了透明支持。
    3,.stream:
    request.stream 返回一个代表请求主体内容的流。

二,响应对象Response

REST framework 还引入了一个

Response 对象
,该对象是一种获取未渲染内容的 TemplateResponse 类型,并使用内容协商来确定正确内容类型返回给客户端。

Response 类的子类是 Django 的 SimpleTemplateResponse。响应对象使用数据进行初始化,数据应由本地 Python 原语组成。REST framework 然后使用标准的 HTTP 内容协商来确定它如何渲染最终响应内容。可以不需要使用 Response 类,如果需要,也可以从视图中返回常规的 HttpResponse 或 StreamingHttpResponse 对象。使用 Response 类只是为返回内容协商的 Web API 响应提供更好的接口,这些响应可以渲染为多种格式。

  • 除非出于某种原因需要大量定制 REST framework,否则应始终对返回 Response 对象的视图使用
    API​​View 类
    @api_view
    函数。这样做可以确保视图执行内容协商,并在视图返回之前为响应选择适当的渲染器。

1,创建响应

语法:

Response(data, status=None, template_name=None, headers=None, content_type=None)

  • data
    :响应的序列化数据。
  • status :响应的状态代码。默认为200。
  • template_name :选择 HTMLRenderer 时使用的模板名称。
  • headers :响应中使用的 HTTP headers 的字典。
  • content_type :响应的内容类型。通常情况下,渲染器会根据内容协商的结果自动设置,但有些情况下需要明确指定内容类型。
  • 如果传递的是未渲染的数据,则它可由任何 Python 原语组成。
  • 由于 Response 类使用的渲染器不能处理复杂的数据类型,例如 Django 模型实例,所以需要在创建 Response 对象之前应先将数据序列化为基本数据类型

2,属性

1,.data
未渲染的、序列化的响应数据。
2,.status_code
HTTP 响应的数字状态码。
3,.content
响应的渲染内容。在访问 .content 之前,必须先调用 .render() 方法。
4,.template_name
template_name (如果提供)。只有当 HTMLRenderer 或其他自定义模板渲染器是响应的渲染器时才需要。
5,.accepted_renderer
用于渲染响应的渲染器实例。从视图返回响应之前由 APIView 或 @api_view 自动设置。
6,.accepted_media_type
内容协商阶段选择的媒体类型。从视图返回响应之前由 APIView 或 @api_view 自动设置。
7,.renderer_context
将传递给渲染器的 .render() 方法的附加的上下文信息的字典。从视图返回响应之前由 APIView 或 @api_view 自动设置。

三,状态码

在您的视图中使用数字 HTTP 状态码并不总是利于代码的阅读,如果写错代码,很容易被忽略。REST framework 为每个状态码提供更明确的标识符,譬如 status 模块中的

HTTP_400_BAD_REQUEST
。使用它们是一个好主意,而不是使用数字标识符。

1,信息 - 1xx (Informational - 1xx)

此类状态码表示临时响应。默认情况下,REST framework 中没有使用 1xx 状态码。

TTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS

2,成功 - 2xx (Successful - 2xx)

此类状态码表明客户端的请求已被成功接收,理解和接受。

HTTP_200_OK
HTTP_201_CREATED
HTTP_202_ACCEPTED
HTTP_203_NON_AUTHORITATIVE_INFORMATION
HTTP_204_NO_CONTENT
HTTP_205_RESET_CONTENT
HTTP_206_PARTIAL_CONTENT
HTTP_207_MULTI_STATUS

3,重定向 - 3xx (Redirection - 3xx)

此类状态码表明用户代理需要采取进一步行动来满足请求。

HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT

4,客户端错误 - 4xx (Client Error - 4xx)

4xx 类的状态码是针对客户端似乎已经出错的情况。除了在响应 HEAD 请求时,服务器应该包括一个实体,其中包含错误情况的解释,以及它是临时的还是永久的。

HTTP_400_BAD_REQUEST
HTTP_401_UNAUTHORIZED
HTTP_402_PAYMENT_REQUIRED
HTTP_403_FORBIDDEN
HTTP_404_NOT_FOUND
HTTP_405_METHOD_NOT_ALLOWED
HTTP_406_NOT_ACCEPTABLE
HTTP_407_PROXY_AUTHENTICATION_REQUIRED
HTTP_408_REQUEST_TIMEOUT
HTTP_409_CONFLICT
HTTP_410_GONE
HTTP_411_LENGTH_REQUIRED
HTTP_412_PRECONDITION_FAILED
HTTP_413_REQUEST_ENTITY_TOO_LARGE
HTTP_414_REQUEST_URI_TOO_LONG
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE
HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS

5,服务器错误 - 5xx (Server Error - 5xx)

以数字 “5” 开头的响应状态码表明服务器意识到它已经错误或无法执行请求的情况。除了在响应 HEAD 请求时,服务器应该包括一个实体,其中包含错误情况的解释,以及它是临时的还是永久的。

HTTP_500_INTERNAL_SERVER_ERROR
HTTP_501_NOT_IMPLEMENTED
HTTP_502_BAD_GATEWAY
HTTP_503_SERVICE_UNAVAILABLE
HTTP_504_GATEWAY_TIMEOUT
HTTP_505_HTTP_VERSION_NOT_SUPPORTED
HTTP_507_INSUFFICIENT_STORAGE
HTTP_511_NETWORK_AUTHENTICATION_REQUIRED

6,帮助函数 (Helper functions)

以下帮助函数可用于识别响应代码的类别。

is_informational()  # 1xx
is_success()        # 2xx
is_redirect()       # 3xx
is_client_error()   # 4xx
is_server_error()   # 5xx

四,包装API序列化视图 (Wrapping API views)

REST框架提供了两个可以用于编写API视图的封装器:

  1. 用于基于函数视图的
    @api_view 装饰器
    。@api_view源码在tutorial\venv\Lib\site-packages\rest_framework\decorators.py。即若用视图函数开发API接口,则必须对视图函数使用@api_view装饰器。
  2. 用于基于类视图的
    APIView 类
    。APIView类源码在tutorial\venv\Lib\site-packages\rest_framework\views.py。即若用视图类开发API接口,则视图类继承APIView类。

五,基于函数的视图

REST framework 允许使用常规的基于函数的视图。它提供了一套简单的装饰器来包装基于函数的视图,以确保它们接收 Request (而不是通常的 Django HttpRequest)实例,并允许它们返回 Response (而不是 Django HttpResponse ),还能配置该请求的处理方式。

1,@api_view()

语法:

@api_view(['GET', 'POST', .......])

基于函数的视图的核心是 api_view 装饰器,它接受视图应该响应的 HTTP 方法列表。
默认情况下,只有 GET 方法会被接受。其他方法将以“405 Method Not Allowed”进行响应。但可以改变:

@api_view(['GET', 'POST'])
def hello_world(request):
if request.method == 'POST':
return Response({"message": "Got some data!", "data": request.data})
return Response({"message": "Hello, world!"})
  • 该视图将使用settings中指定的默认渲染器,解析器,认证类等。

2,API 策略装饰器 (API policy decorators)

为了覆盖默认设置,REST framework 提供了一系列可以添加到视图中的附加装饰器。这些必须在 @api_view 装饰器之后。

要创建一个使用限流来确保它每天只能由特定用户调用一次的视图,请使用 @throttle_classes 装饰器,传递一个限流类列表:
from rest_framework.decorators import api_view, throttle_classes
from rest_framework.throttling import UserRateThrottle

class OncePerDayUserThrottle(UserRateThrottle):
rate = '1/day'

@api_view(['GET'])
@throttle_classes([OncePerDayUserThrottle])
def view(request):
return Response({"message": "Hello for today! See you tomorrow!"})

可用的装饰器还有:

  • @renderer_classes(…)
  • @parser_classes(…)
  • @authentication_classes(…)
  • @throttle_classes(…)
  • @permission_classes(…)

六,使用基于函数的视图

1,重构基于函数的视图

@api_view(['GET', 'POST'])
def snippet_list(request):
"""
列出所有的代码 snippet,或创建一个新的 snippet。
"""
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True) #前面提到,data部分既可以是模型内容,也可以是查询集
return Response(serializer.data)

elif request.method == 'POST':
serializer = SnippetSerializer(data=request.data)
if serializer.is_valid():
serializer.save()	# 验证无误后,存入模型数据库
print(serializer)
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
"""
获取,更新或删除一个代码 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)
  • 都使用了Resopnse进行相应,使内容更可读,即返回带有数据的响应对象,这允许 REST framework 将响应渲染成正确的内容类型。
  • 使用了指定的状态码,这让响应更加明显。
  • 不再显式地将请求或响应绑定到指定的类型。request.data 可以处理传入的多种格式的请求,

2,为网址添加可选的格式后缀

为了利用我们的响应不再被硬连接到单个内容类型的事实,我们可以将对格式后缀的支持添加到我们的API端点。
使用格式后缀,为我们提供了明确指向给定格式的 URL,如http://example.com/api/items/4.json。
1,对两个视图函数都追加一个参数,format=None:

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

2,在snippet/urls.py 文件的 urls 基础上追加format_suffix_patterns :

from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
url(r'^snippets/$', views.snippet_list),
url(r'^snippets/(?P<pk>[0-9]+)$', views.snippet_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

3,运行:



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: