Request objects
REST框架引入了Request对象来
扩展常规的HttpRequest
,并提供更灵活的请求解析。Request
对象的核心功能是request.data
属性,这与request.POST相似,但对
使用Web API更有用。
request.POST # Only handles form data. Only works for ‘POST‘ method. request.data # Handles arbitrary data. Works for ‘POST‘, ‘PUT‘ and ‘PATCH‘ methods.
REST框架还引入了一个Response
对象,它是TemplateResponse的一种类型,它
使用未渲染的内容,并使用内容协商来确定正确的内容类型以返回给客户端。
return Response(data) # Renders to content type as requested by the client.
在您的视图中使用数字HTTP状态码并不总是利于阅读,如果您收到 an error code wrong你将很难注意到。 REST框架为每一个状态码更明确的标识符,如status
模块中的HTTP_400_BAD_REQUEST。
使用这些标识符比使用数字标识符要好的多。
Wrapping API views
REST框架提供了两个可用于编写API视图的wrappers。
- The
@api_view
装饰器对function-based views有效。 - The
APIView
class对class-based views有效。
这些wrappers提供了一些功能,例如确保您在视图中接收Request
实例,并将上下文添加到Response
对象,以便可以执行content negotiation。
The wrappers also provide behaviour such as returning 405 Method Not Allowed
responses when appropriate, and handling any ParseError
exception that occurs when accessing request.data
with malformed input.
Pulling it all together
好的,我们开始使用这些新的组件来写几个视图。
views.py中
不再需要JSONResponse
class, 所以请删除它。一旦完成这些,我们就可以开始重构我们视图了.
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)
我们的实例视图比以前的例子有所改进。这更加简明扼要,现在的代码与我们使用的Forms API非常相似。我们还使用命名的状态码,这使得响应意义更加明显。
以下是views.py
模块中单个的代码段视图。
@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)
这应该都是非常熟悉的 - 与常规的Django视图并没有什么不同。
请注意,我们不再明确地将我们的请求或响应绑定到一个给定的内容类型。request.data
能够处理输入的 json
requests,但它也可以处理其他格式。同样,我们使用数据返回响应对象,但允许REST框架将响应渲染成正确的内容类型。
Adding optional format suffixes to our URLs
我们的响应不再与单一内容类型连接,为了充分利用这个事实,我们可以为API端点添加一些格式后缀。使用格式后缀给urls明确指定一个格式,这意味着我们的API将能够处理诸如http://example.com/api/items/4.json之类的urls。
首先在两个视图中添加一个format
关键字参数,就像这样。
def snippet_list(request, format=None):
and
def snippet_detail(request, pk, format=None):
Now现在稍微更新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)
我们不一定需要添加这些额外的url模式,但它给了我们一个简单,干净的方式来引用特定的格式。
How‘s it looking?
从命令行开始测试API,就像我们在第1部分中所做的那样。一切工作都非常相似,尽管如果发送无效请求,我们已经有了更好的错误处理。
我们可以像以前一样获取所有片段的列表。
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 header
来控制响应的格式:
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
或者通过附加格式后缀:
http http://127.0.0.1:8000/snippets.json # JSON suffix http http://127.0.0.1:8000/snippets.api # Browsable API suffix
Similarly,类似地,我们可以使用Content-Type header
来控制我们发送的请求的格式。
# 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" }
If you add a --debug
switch to the http
requests above, you will be able to see the request type in request headers.
如果您向上述的http requests添加--debug
,你将可以在请求头中查看请求类型。
现在,在Web浏览器中打开API,访问http://127.0.0.1:8000/snippets/。