请求 和 响应
请求对象
REST框架 引进了一个 Request 对象,它继承于 HttpRequest 类,提供了更加灵活的的请求解析。我们用到的主要功能有 request.data 属性,和 request.POST 差不多,但是对于 Web API 来说,request.data 更有用。
request.POST # 只对表单数据有效,并且只在 POST 请求生效
request.data # 可以处理任意数据,'POST'、'PUT' 和 'PATCH' 方法都可以生效。
响应对象
REST框架 同时也引进了一个 Response 对象,它继承自 TemplateResponse 对象,他可以根据内容协商从而决定返回给客户端的未渲染内容。
状态码
在代码使用数字作为 HTTP 状态码对于阅读者来说是一件噩梦的事情,并且你可能会经常弄错错误码。REST框架在 status 模块中为每个状态码都提供了明确的标示,例如
HTTP_400_BAD_REQUEST
。在代码中使用这个标示来替代数字状态码对于开发者来说是一个良好的习惯。
包装 API views
REST 框架提供了两个可以用于编写 API views 的包装器:
- @api_view 装饰器用于基于函数的 views
- APIView 类用于基于类的 views
这些包装器提供了一些函数确保你可以接受到 Request 对象,同时在 Response 中添加上下文,以便内容协商可以正常得工作。
同时,当遇到 ParseError 时,可能会导致 request.data 的输入异常的时候,这些包装器还会适时得返回
405 Method Not Allowed
。
使用合集
OK,光说不练假把式,继续以快速入门一中的实例为例,继续改进。
首先,需要修改的是
views.py
,修改后的代码如下:
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 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)
@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
Retrieve, update or delete a snippet instance.
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)
主要改进的地方是增加了装饰器 api_views,使用了 Request 和 Response对象,去除了 JSONResponse 对象,将状态码从数字换成了状态标识。
附加后缀格式
目前为止,我们的REST API 只能返回一种 json 格式,假设我们需要根据不同的情景返回不同的格式,那么我们可以通过一个后缀来处理,例如
- http://example.com/api/items/4/.json 返回 json 格式
- http://example.com/api/items/4/.html 返回 html 格式
这个我们可以通过 REST 框架 的后缀格式化实现。
首先,我们需要修改 views 的定义方式:
def snippet_list(request, format=None):
def snippet_detail(request, pk, format=None):
注意到,每个 views 函数都增加了一个 format 的参数。
然后修改 urls.py,修改后长这样:
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)
其实就是增加了一个 format_suffix_patterns,用于添加后缀处理。
结果展示
OK,到这里,我们就算完成了本章节的内容,我们使用 runserver 来运行服务器:
python manage.py runsever
然后分别在浏览器中输入以下地址,看看有什么不一样?
http://localhost:8000/snippets/.json
http://localhost:8000/snippets/.api
问题
有可能你访问:
http://localhost:8000/snippets/.api
时,会报出这样的一个错误:
'url' is not a valid tag or filter in tag library 'future'
这时候,你需要打开 rest_framework 模块下的
rest_frameworktemplatesrest_frameworkbase.html
模板文件,然后去除第一行中的:
{% load url from future %}
然后重新刷新一下浏览器,问题解决!