Django-Rest-Framework 教程: 2. Requests 和 Responses

在我们的博客中, 记录了我们在开发过程中所使用的技术和遇到的问题, 希望作为其他开发和设计者的一个学习交流平台.

Django-Rest-Framework 教程: 2. Requests 和 Responses


接着上篇的内容, 本篇中, 我们进一步介绍Django-rest-framework的其他核心部件. 首先我们来做准备工作:

Request

django-rest-framework中引入了新的Request类, 该Request继承自Django的HttpRequest, 并提供了更多灵活的request处理功能. 比如request.DATA属性便是专门用作Web API的属性, 类似于request.POST.

    request.POST  # 只处理form数据; 只接受HTML 'POST'动作.
    request.DATA  # 处理特定数据; 接受HTML 'POST', 'PUT' 和 'PATCH' 动作.

状态码 (status codes)

django-rest-framework为每一个状态码都提供了打包好的, 更为精确的状态码完整描述供我们使用, 比如HTTP_400_BAD_REQUEST.

API views

django-rest-framework为function_based_view和class_based_view分别提供了@api_view修饰器和APIView类. 这些wrapper代码, 保证了view接收Request实例, 并会自动添加context至Response中. 这些wrapper还能自动返回正确的状态码和详细信息.

1. 开始

接着之前的views.py, 在这里, 我们已经不需要JSONResponse了, 因此, 首先将其删除. 然后修改views.py中的snippet_list view:

    snippets/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=status.HTTP_201_CREATED)
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

以上代码相对于教程1中的代码更为简洁. 可以看到代码与form API的使用十分相似, 我们还使用了内置的状态码, 使返回的response意义更为清晰.

对于单独的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)

从以上代码中可以看到, 我们不再指明request和response中的内容类型. request.DATA即可用来处理json数据类型类型, 也可以处理yaml或其他数据类型. 同时, django-rest-framework也能根据不同情况, 再response呈现正确的数据类型.

2. 使用其他数据格式

为了展示如何多数据格式的支持, 接下来, 我们为url添加后缀: http://example.com/api/items/4.json

为snippets/view.py中的snippet_list和snippet_detail增加format参数

    def snippet_list(request, format=None):
        ...

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

更新urls.py:

    from django.conf.urls import patterns, url
    from rest_framework.urlpatterns import format_suffix_patterns

    urlpatterns = patterns('snippets.views',
        url(r'^snippets/$', 'snippet_list'),
        url(r'^snippets/(?P<pk>[0-9]+)$', 'snippet_detail'),
    )

    urlpatterns = format_suffix_patterns(urlpatterns)

以上代码是可选的, 实际上我们并不需要添加这些url pattern就能实现多数据格式的支持. 但添加之后使得使用时更加直观.

3. 测试

我们可以通过前篇教程中的方式测试, 获取所有snippet:

curl http://127.0.0.1:8000/snippets/

[{"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头部信息控制response返回格式:

    curl http://127.0.0.1:8000/snippets/ -H 'Accept: application/json'  # JSON
    curl http://127.0.0.1:8000/snippets/ -H 'Accept: text/html'         # HTML

或者使用后缀控制返回格式:

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

通过修改request的Content-Type头部, 控制格式:

    # 使用form data POST
    curl -X POST http://127.0.0.1:8000/snippets/ -d "code=print 123"

    {"id": 3, "title": "", "code": "print 123", "linenos": false, "language": "python", "style": "friendly"}

    # 使用JSON POST
    curl -X POST http://127.0.0.1:8000/snippets/ -d '{"code": "print 456"}' -H "Content-Type: application/json"

    {"id": 4, "title": "", "code": "print 456", "linenos": true, "language": "python", "style": "friendly"}

或者直接在浏览器中打开:

    http://127.0.0.1:8000/snippets/

原文链接: http://weiguda.com/blog/20/