这一部分可以让返回的api信息以两种格式呈现:.json和.api
REST框架的核心部分。我们来介绍几个基本的组成部分。
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.
Response objects
REST框架还引入了Response
对象,which is a type of TemplateResponse
that takes unrendered content and uses content negotiation to determine the correct content type to return to the client.
return Response(data) # Renders to content type as requested by the client.
Status codes
在您的视图中使用数字HTTP状态码并不总是利于阅读,如果您收到 an error code wrong你将很难注意到。 REST框架为每一个状态码更明确的标识符,如status
模块中的HTTP_400_BAD_REQUEST。
使用这些标识符比使用数字标识符要好的多。
HTTP_100_CONTINUE = 100 HTTP_101_SWITCHING_PROTOCOLS = 101 HTTP_200_OK = 200 HTTP_201_CREATED = 201 HTTP_202_ACCEPTED = 202 HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203 HTTP_204_NO_CONTENT = 204 HTTP_205_RESET_CONTENT = 205 HTTP_206_PARTIAL_CONTENT = 206 HTTP_207_MULTI_STATUS = 207 HTTP_300_MULTIPLE_CHOICES = 300 HTTP_301_MOVED_PERMANENTLY = 301 HTTP_302_FOUND = 302 HTTP_303_SEE_OTHER = 303 HTTP_304_NOT_MODIFIED = 304 HTTP_305_USE_PROXY = 305 HTTP_306_RESERVED = 306 HTTP_307_TEMPORARY_REDIRECT = 307 HTTP_400_BAD_REQUEST = 400 HTTP_401_UNAUTHORIZED = 401 HTTP_402_PAYMENT_REQUIRED = 402 HTTP_403_FORBIDDEN = 403 HTTP_404_NOT_FOUND = 404 HTTP_405_METHOD_NOT_ALLOWED = 405 HTTP_406_NOT_ACCEPTABLE = 406 HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407 HTTP_408_REQUEST_TIMEOUT = 408 HTTP_409_CONFLICT = 409 HTTP_410_GONE = 410 HTTP_411_LENGTH_REQUIRED = 411 HTTP_412_PRECONDITION_FAILED = 412 HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413 HTTP_414_REQUEST_URI_TOO_LONG = 414 HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415 HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416 HTTP_417_EXPECTATION_FAILED = 417 HTTP_422_UNPROCESSABLE_ENTITY = 422 HTTP_423_LOCKED = 423 HTTP_424_FAILED_DEPENDENCY = 424 HTTP_428_PRECONDITION_REQUIRED = 428 HTTP_429_TOO_MANY_REQUESTS = 429 HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431 HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451 HTTP_500_INTERNAL_SERVER_ERROR = 500 HTTP_501_NOT_IMPLEMENTED = 501 HTTP_502_BAD_GATEWAY = 502 HTTP_503_SERVICE_UNAVAILABLE = 503 HTTP_504_GATEWAY_TIMEOUT = 504 HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505 HTTP_507_INSUFFICIENT_STORAGE = 507 HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511
Wrapping API views
REST框架提供了两个可用于编写API视图的wrappers。
- 适用于function-based views的
@api_view
。 - 适用于class-based views的
APIView
。
这些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,但它也可以处理其他格式。同样,we're returning response objects with data,但允许REST框架将响应渲染成正确的内容类型。
给url添加可选的格式后缀
我们的响应不再与单一内容类型连接,为了充分利用这个事实,我们可以为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):
然后更新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" ", "linenos": false, "language": "python", "style": "friendly" }, { "id": 2, "title": "", "code": "print "hello, world" ", "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
类似地,我们可以使用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" }
如果您向上述的http requests添加--debug
,你将可以在请求头中查看请求类型。
现在,在Web浏览器中打开API,访问http://127.0.0.1:8000/snippets/。