django-rest-framework指南:Requests and Responses

Posted 黑猫-警长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django-rest-framework指南:Requests and Responses相关的知识,希望对你有一定的参考价值。

Tutorial 2: Requests and Responses

我要开始接触REST framework的核心了.先介绍一些基本的组件.

Request objects

REST framework引进了一个继承自HttpRequst的Request对象,并提供了更灵活的请求解析.Request对象的核心功能时request.data属性,它和request.POST有点相似,但更适合于WEB API.

request.POST  # 只获取表单数据,只能用于POST方法
request.data  # 获取所有数据,能用于POST,PUT和PATCH方法

Response objects

REST framework也引进了Response对象,它是TemplateResponse类型的,通过未渲染内容和内容协议(content negotiation)来决定返回到客户端的正确的content type.

return Response(data)  # 根据客户端的请求来渲染content type

Status codes

在视图里使用HTTP状态码通常不易于代码阅读,写错状态码也不容易发现.REST framework为每个状态码提供了更显式的标识,比如status模块里的HTTP_404_BAD_REQUEST.使用他们比使用数字的状态码要好.

Wrapping API views

REST framework提供了2种wrapper用于写API视图.
1. @api_view装饰器,用于视图函数.
2. APIView类,用于视图类.

这些wrapper提供了一些功能,例如确保在视图中能接受Request实例,并将内容添加到Response对象,这样就能完成内容协议(content negotiation).
这些wrapper也提供了一些动作(behaviour),例如适当的时候响应405 Method Not Allowed,当解析的request.data格式不正确时抛出ParseError异常.

Pulling it all together

ok,让我们开始利用这些新组件来写一些视图.
我们不再需要JSONResponse类和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):
    '''
    列出所有snippet,或者创建一个新的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=HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

这是对上一个例子的改进的view.稍微简洁了点,感觉和Form API有点像.我们也使用了命名的状态码,使响应的意思更明显.
下面是views.py模块中,针对单个的snippet的代码.

@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
    '''
    查找,更新或删除一个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视图没有很多不同.
注意:我们不再需要显式的声明请求或相应的content type.request.data能处理json请求,同样也能处理其他格式.同样的返回带有数据的响应对象,REST framework能为我们用正确的格式渲染响应.

Adding optional format suffixed to our URLs(为URL添加可选的format后缀)

To take advantage of the fact that our responses are no longer hardwired to a single content type let’s add support for format suffixes to our API endpoints. Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as http://example.com/api/items/4/.json.
在view里添加关键字参数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'^sinppets/(?P<pk>[0-9]+)/$', views.snippets_detail),
]

urlpatterns = format_suffix_patterns(urlpatterns)

不是一定要这样使用,但是这种方法简洁实用.

How is it looking?

就像在指南(1)中做的那样,我们来测试一下API.一切都很相似,而且如果发送了无效的请求也有错误处理了.
我们会获得一个snippet列表,就像之前

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

或者用format后缀:

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头信息来控制请求格式.

# 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://127.0.0.1:8000/snippets/,就可以在浏览器里打来API了.

Browsability

因为API是根据客户端请求来确定相应的内容格式(content type),所以如果用浏览器,默认情况下返回HTML格式的资源.
web-browsable API易于使用,能使开发和使用API更容易.这能使其他开发者查看和使用你的API更方便,简单.

What is next?

在指南(3),我们将使用视图类,这样能少些很多代码.

以上是关于django-rest-framework指南:Requests and Responses的主要内容,如果未能解决你的问题,请参考以下文章

django-rest-framework指南:Class Based Views(类视图)

在 django-rest-framework 中插入 django-allauth 作为端点

如何将命名空间 url 添加到 django-rest-framework 路由器视图集

django-rest-framework:如何序列化已经包含 JSON 的字段?

django-rest-framework 是不是提供管理站点来管理模型?

断言错误:Django-rest-Framework