Django REST framework---请求和响应

Django REST framework---请求和响应


 【Request对象】

概念:

  平时我们在写Django的视图函数的时候,都会带上一个request参数,这样就能处理平时搭建网站时,浏览器访问网页时发出的常规的HttpRequest。但是现在我们导入了django-rest-framework,它能够对request进行拓展,并且提供更灵活的请求解析。

区别:

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

实例:

  

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

【Response对象】

说明:

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

举例:

@csrf_exempt
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 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)

【状态码】

说明:  

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

【包装API视图】

  

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

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

这些包装提供了一些功能,让我们省去很多工作。比如说确保你在视图中收到Request对象或在你的Response对象中添加上下文,这样就能实现内容通信。

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

紧接着我们再次的重构views.py,当使用装饰器的时候就不需要使用JOSNresponse

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

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

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

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

【向URL添加可选格式后缀】

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

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

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

接下来就是更改我们urls.py文件增加格式后缀的一种的模式

from django.conf.urls import url
from . import views
from rest_framework.urlpatterns import format_suffix_patterns

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

urlpatterns = format_suffix_patterns(urlpatterns)

 对我们上述的Api进行测试

通过启动服务器的方式

还可以在终端下使用http

lee@lee:~/PycharmProjects/Djdemo$ source venv/bin/activate
(venv) lee@lee:~/PycharmProjects/Djdemo$ http http://127.0.0.1:8000/snippets/
HTTP/1.1 200 OK
Allow: OPTIONS, GET, POST
Content-Length: 317
Content-Type: application/json
Date: Mon, 06 Aug 2018 15:29:29 GMT
Server: WSGIServer/0.2 CPython/3.5.2
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

[
    {
        "code": "foo = \"bar\"\n",
        "id": 3,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    },
    {
        "code": "print \"hello, world\"\n",
        "id": 4,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    },
    {
        "code": "print \"hello, world\"",
        "id": 5,
        "language": "python",
        "linenos": false,
        "style": "friendly",
        "title": ""
    }
]

我们可以通过使用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

或者通过附加格式后缀:

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标头控制我们发送的请求的格式

(venv) lee@lee:~/PycharmProjects/Djdemo$ http --form POST http://127.0.0.1:8000/snippets/ code="print 123"
HTTP/1.1 201 Created
Allow: OPTIONS, GET, POST
Content-Length: 93
Content-Type: application/json
Date: Mon, 06 Aug 2018 15:36:11 GMT
Server: WSGIServer/0.2 CPython/3.5.2
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

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

--------------

(venv) lee@lee:~/PycharmProjects/Djdemo$ http --json POST http://127.0.0.1:8000/snippets/ code="print 456"
HTTP/1.1 201 Created
Allow: OPTIONS, GET, POST
Content-Length: 93
Content-Type: application/json
Date: Mon, 06 Aug 2018 15:36:50 GMT
Server: WSGIServer/0.2 CPython/3.5.2
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
    "code": "print 456",
    "id": 7,
    "language": "python",
    "linenos": false,
    "style": "friendly",
    "title": ""
}

如果报错:请参照 https://www.cnblogs.com/youleng/p/9117920.html

--------将继续完善

猜你喜欢

转载自www.cnblogs.com/Echo-O/p/9430038.html