django-rest-framework之请求与响应

前言:在上一篇文章,已经实现了访问指定URL就返回了指定的数据,这也体现了RESTful API的一个理念,每个URL表明着一个资源。固然咱们还知道RESTful API的另外一个特性就是,发送不一样的请求动做,会返还不一样的响应,这篇文章就讲一下django-rest-framework这个工具在这方面给咱们带来的便捷操做。html

1、Request对象

平时咱们在写Django的视图函数的时候,都会带上一个request参数,这样就能处理平时搭建网站时,浏览器访问网页时发出的常规的HttpRequest。可是如今咱们导入了django-rest-framework,它可以对request进行拓展,而且提供更灵活的请求解析。这个特性体如今哪呢?请看下面这个例子:前端

request.POST  # Only handles form data.  Only works for 'POST' method.
request.data  # Handles arbitrary(任意的) data.  Works for 'POST', 'PUT' and 'PATCH' methods.

request.POST只能处理前端发起的POST请求,只能处理表单提交的数据。而request.data能够处理任意数据,而不仅仅是前端提交的表单数据,可用于post, put, patch请求。python

 

2、Response对象

和request对象同样,django-rest-framework也对其进行了很实用的拓展,在我上一篇文章的snippets/views.py中,咱们导入了JsonResponse用于返回json格式的响应,在视图函数中是这样的:web

@csrf_exempt
def snippet_list(request):
    """
    because we want to be able to POST to this view from clients
    that won't have a CSRF token we need to mark the view as csrf_exempt
    List all code snippets, or create a new snippet.
    """
    if request.method == "GET":
        snippets = Snippet.objects.all()
        serializer = SnippetSerializer(snippets, many=True)
        return JsonResponse(serializer.data, safe=False)

    elif request.method == "POST":
        data = JSONParser().parse(request)
        serializer = SnippetSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return JsonResponse(serializer.data, status=201)
        return JsonResponse(serializer.errors, status=400)
View Code

也就是说,在return的时候就须要指明json格式,这样显得很不实用并且很单一,因此通过拓展后的Reponse对象就很方便了,它会根据客户端的请求头部信息来肯定正确的内容类型以返回给客户端。只需以下代码:django

return Response(data)  # Renders to content type as requested by the client. 

  

3、状态码

咱们知道发送http请求时会返回各类各样的状态吗,可是都是简单的数字,好比200、404等,这些纯数字标识符有时候可能不够明确或者客户端在使用的时候不清楚错误信息甚至是没注意看不到,因此django-rest-framework也对此进行了优化,状态码会是HTTP_400_BAD_REQUEST、HTTP_404_NOT_FOUND这种,极大的提升可读性json

 

4、包装API视图

REST框架提供了两个可用于编写API视图的包装器。api

  • @api_view装饰器用于处理基于函数的视图
  • APIView类用在基于视图的类上

这些包装提供了一些功能,让咱们省去不少工做。好比说确保你在视图中收到Request对象或在你的Response对象中添加上下文,这样就能实现内容通讯。浏览器

另外装饰器能够在接收到输入错误的request.data时抛出ParseError异常,或者在适当的时候返回405 Method Not Allowed状态码。app

 

5、Pulling it all together(使用)

Okay, let's go ahead and start using these new components to write a few views.框架

We don't need our JSONResponse class in views.py any more, so go ahead and delete that. Once that's done we can start refactoring(重构) our views slightly.

在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)

能够看出,通过改进的代码已经把上面所说的几个django-rest-framework带来的特性都应用起来了,咱们能够看出程序代码量变少,而且能处理的状况更多了。 好比说,在本来的视图函数snippet_detail中,处理'PUT'请求的时候,须要先解析前端发来的json格式的数据再进一步处理:

data = JSONParser().parse(request)
serializer = SnippetSerializer(snippet, data=data)

也就是说须要分红两步实现,并且这里有一个限制就是只能解析json格式的数据流。而改进后的程序只需一行代码:

serializer = SnippetSerializer(data=request.data)

 

request.data can handle incoming json requests, but it can also handle other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.

request.data就能够获取到提交过来的数据了,而且能够处理各类数据和各类请求动做,方便了开发。还有在return的时候也不须要指定json格式了,由本来的:

return JsonResponse(serializer.data, status=201)

改为了

return Response(serializer.data,status=status.HTTP_201_CREATED)

这也意味着返回给客户端的能够是json或者html等格式的内容,返回HTML格式的内容的话,会在浏览器返回通过渲染的、更美观的页面。同时能够看出状态码也改进成了django-rest-framework给咱们带来的可读性更高的状态标识码,以上这些措施都很大程度的提升了对客户的友好度。

对于另外一个视图函数的修改也是一样的原理,这里就不作一样的讲解了,代码以下:

@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)
View Code

以上就是对原有的常规的Django视图函数的改进。

总结一下就是处理request提交过来的数据不须要必定是json格式的数据,返回的响应也不须要必定是json数据,也能够是通过渲染的HTML页面。稍后就会示范使用。

 

6、向URL添加可选的格式后缀

既然上面已经说了返回给客户端的Response但是json或者是HTML等格式的内容,那么用户在使用的时候是如何指定返回哪一种格式的内容呢,那就是在URL的最后加上后缀。好比http://127.0.0.1:8000/snippets.json,这样就是用户本身指定了返回json格式的Response,而不是咱们在后台指定返回固定的格式。

只需对咱们的程序稍加改进就能够了,在两个视图函数添加关键词参数format:

def snippet_list(request, format=None):

and

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

Now update the urls.py file slightly, to append a set of format_suffix_patterns(格式后缀模式) in addition to the existing URLs.

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)

 

7、How's it looking?

Go ahead and test the API from the command line, as we did in tutorial part 1. Everything is working pretty similarly, although we've got some nicer error handling if we send invalid requests.

We can get a list of all of the snippets, as before.

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" } ]

We can control the format of the response that we get back, either by using the 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

Or by appending a format suffix:

http http://127.0.0.1:8000/snippets.json  # JSON suffix
http http://127.0.0.1:8000/snippets.api   # Browsable API suffix

Similarly, we can control the format of the request that we send, using the 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.

Now go and open the API in a web browser, by visiting http://127.0.0.1:8000/snippets/.

 

Browsability

Because the API chooses the content type of the response based on the client request, it will, by default, return an HTML-formatted representation of the resource when that resource is requested by a web browser. This allows for the API to return a fully web-browsable HTML representation.

Having a web-browsable API is a huge usability win, and makes developing and using your API much easier. It also dramatically lowers the barrier-to-entry for other developers wanting to inspect and work with your API.

See the browsable api topic for more information about the browsable API feature and how to customize it.

浏览功能(中文)

因为API根据客户端请求选择响应的内容类型,所以默认状况下,当Web浏览器请求资源时,将返回HTML格式的资源表示形式这容许API返回彻底的可浏览网页的HTML表示。

拥有一个可浏览网页的API是一个巨大的可用性胜利,而且使开发和使用您的API更容易。它也大大下降了想要检查和使用您的API的其余开发人员的入门障碍。

有关浏览的API功能以及如何对其进行定制的更多信息,请参阅可浏览的api主题。

相关文章
相关标签/搜索