请求和响应
请求对象(Request objects)
REST框架引入了一个扩展了常规HttpRequest
的Request
对象,并提供了更灵活的请求解析。Request
对象的核心功能是request.data
属性,它与request.POST
类似,但对于使用Web API更为有用。
request.POST # 只处理表单数据 只适用于'POST'方法 request.data # 处理任意数据 适用于'POST','PUT'和'PATCH'方法
响应对象(Response objects)
REST框架还引入了一个Response
对象,这是一种获取未渲染(unrendered)内容的TemplateResponse
类型,并使用内容协商来确定返回给客户端的正确内容类型
return Response(data) # 渲染成客户端请求的内容类型。
状态码(Status codes)
在你的视图(views)中使用纯数字的HTTP 状态码并不总是那么容易被理解。而且如果错误代码出错,很容易被忽略。REST框架为status
模块中的每个状态代码(如HTTP_400_BAD_REQUEST
)提供更明确的标识符。使用它们来代替纯数字的HTTP状态码是个很好的主意。
包装(wrapping)API视图
REST框架提供了两个可用于编写API视图的包装器(wrappers)。
-
用于基于函数视图的
@api_view
装饰器。 -
用于基于类视图的
APIView
类。
这些包装器提供了一些功能,例如确保你在视图中接收到Request
实例,并将上下文添加到Response
,以便可以执行内容协商。
包装器还提供了诸如在适当时候返回405 Method Not Allowed
响应,并处理在使用格式错误的输入来访问request.data
时发生的任何ParseError
异常。
正式开始
好了,我们要创建一个用于创建简单Web API的app。
python manage.py startapp snippets
我们需要将新建的snippets
app和rest_framework
app添加到INSTALLED_APPS
。让我们编辑tutorial/settings.py
文件:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'quickstart.apps.QuickstartConfig', 'snippets.apps.SnippetsConfig', 'rest_framework', ]
请注意如果你使用的Django版本低于1.9,你需要使用snippets.apps.SnippetsConfig
替换snippets
。
创建一个model
组合在一起
好的,我们开始使用这些新的组件来写几个视图。
我们在views.py
中不再需要JSONResponse
类了,所以把它删除掉。删除之后,我们就可以开始重构我们的视图了。
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)
我们的实例视图是我们之前例子的改良版。简明了很多,并且目前的代码和我们使用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框架渲染响应成正确的内容类型。
在我们的链接(URLs)后添加可选格式后缀
为了利用我们的响应内容不再是单一格式的事实,我们应该为我们的API尾部添加格式后缀。用格式后缀给我们明确参考指定格式的URL,这意味着我们的API能够处理像http://example.com/api/items/4/.json
一样的链接。 在视图函数中添加一个format
参数,像这样:
def snippet_list(request, format=None):
和
def snippet_detail(request, pk, format=None):
现在可以很快更新urls.py文件,在已经存在的URL中添加一个格式后缀模式(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)
我们不必添加额外的URL模式,但是它给我们简单、清楚的方式渲染除特定的格式。
看看吧
和教程第一部分一样,我们要开始从命令行测试API。虽然我们能在发送无效的请求时更妥当处理错误,但是现在一切都做的够好了。 我们能想之前一样获取所有的snippets列表。
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
或者在URL后添加格式后缀:
http http://127.0.0.1:8000/snippets.json # JSON 后缀 http http://127.0.0.1:8000/snippets.api # 浏览用的 API 后缀
同样地,我们可以控制我们发送的请求格式,用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" }
你也可以从浏览器打开API,通过访问http://127.0.0.1:8000/snippets/。
Browsability
因为API是基于客户端请求来选择响应内容的类型,所以默认情况下,在Web浏览器访问资源时,API返回HTML格式的资源。这语序API返回完全可以网页浏览的HTML。 有可以网页浏览API是很好的,这使开发和使用你的API更简单,这也为其他想要查看和使用你的API的开发者大大降低了门槛。 关于可浏览API的特性和如何自定义可浏览API,请见可浏览API话题。
接下来要干什么?
我们基于视图用类,并且看看普通的视图我们如何减少代码。
扫码关注微信公众号 “小樊Study”获取更多
直男们,扫我送女友哟!