这一篇我们开始讲解RESTframework框架的核心内容。让我们介绍一些基本的构建模块。

Request对象

REST framework引入了Request对象,它继承自常规的HttpRequest,并提供更加灵活的请求解析。Request对象的核心功能是request.data参数,类似于request.POST

1
2
request.POST # 只能处理表单数据. 只能处理‘POST’请求
request.data # 处理任何数据. 处理‘POST’,'PUT',‘PATCH’.

Response对象

REST framework也引入了Response对象,使用内容协商来决定返回给客户端的数据类型。

1
return Response(data) # 返回客户端请求的数据类型

状态码

在视图中使用纯数字的HTTP状态码可读性差,并且不容易发现错误。REST framework为每个状态码提供了明确的标识符,例如status模块中的HTTP_400_BAD_REQUEST

装饰API视图

REST framework提供了两个可用于编写视图API的封装:

  1. @api_view装饰视图函数
  2. APIView类可用作视图的基类

这些封装提供了一些额外的功能,例如确保了你的视图接受到Request实例,执行内容协商,并且把内容添加到Response对象中。

也会适当得返回405 Method Not Allowed响应,以及处理request.data格式不正确的ParseError异常。

把他们整合在一起

让我们继续使用这些新组件写一些视图函数。

views.py中我们不再需要JSONResponse类,所以删了它。完成后我们可以对我们的视图函数进行轻微的重构了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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)

我们改进了之前的例子。变得更加简洁,代码风格也跟Forms API很像,同时使用了命名的状态码这使得响应内容更加明确。

单个页面的视图函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@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.data可以处理传进来的json请求,也可以处理其他数据格式。同样,我们返回包含数据的响应时,REST framework会将数据渲染成恰当的数据格式。

给URLs添加可选的格式后缀

利用上面的特性,我们的响应可以返回多种数据类型,让我们为API端点添加格式后缀的支持。意味着我们的API可以出来这种URLs http://example.com/api/items/4.json.

给所有的视图函数添加format关键字参数,就像

1
def snippet_list(request, format=None):

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

现在更新一下snippets/urls.py文件,将现有的URLs添加到一组format_suffix_patterns中。

1
2
3
4
5
6
7
8
9
10
from django.urls import path
from snippets import views
from rest_framework.urlpatterns import format_suffix_patterns
urlpatterns = [
path('snippets/', views.snippet_list),
path('snippets/<int:pk>/', views.snippet_detail),
]
urlpatterns = format_suffix_patterns(urlpatterns)

它提供了一种简单的引用方式,因此我们不需要再添加额外的url模式。

看起来怎么样?

继续在命令行中测试我们的API。一切好像没什么变化,除了我们发生无效的请求时多了一些很好的错误处理。

我们可以像之前一样获得所有代码片段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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头部字段,我们可以控制响应的格式:

1
2
http http://127.0.0.1:8000/snippets/ Accept:application/json # 请求JSON数据
http http://127.0.0.1:8000/snippets/ Accept:text/html # 请求HTML数据

或者添加格式后缀:

1
2
http http://127.0.0.1:8000/snippets.json # JSON 后缀
http http://127.0.0.1:8000/snippets.api # Browsable API suffix

同样,也可以使用Content-Type头部字段设置我们所发送的数据的数据格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# POST 表单数据
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 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命令前添加--debug,你还能在请求头部看到请求类型。

现在打开浏览器,访问 http://127.0.0.1:8000/snippets/.

Browsability

API的响应类型取决于客户端的请求,但是默认情况下,当浏览器请求一个资源时会返回一个HTML格式的响应。

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

想要了解更多可查阅browsable api

下一步是什么?

教程3,我们将会使用基于类的视图,并且学习如何通过视图减少大量的代码。

留言

⬆︎TOP