RESTful Web Services:——2:创建 API 函数视图

导读:本篇文章讲解 RESTful Web Services:——2:创建 API 函数视图,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目前项目结构如下:
在这里插入图片描述

1,理解Django是如何工作的

当Django服务器接收到HTTP请求时,Django创建一个django.http.HttpRequest对象。该对象的实例包含有关请求的元数据,其中就包含HTTP动作,例如GETPOSTPUT,可通过method属性来获取。

当Django加载适当的处理请求的视图时,它将HttpRequest的实例作为第一个参数传递给视图函数。视图函数必须返回django.http.HttpResponse对象的实例,该对象的实例包含有关响应的元数据,其中包含对响应内容的编码格式,可通过content_type属性来设置。

2,用视图与请求方法理解CRUD

先创建与序列化类联系的视图,通过一个简单的例子理解Django与DRF是如何协同工作的。

restful01/toys/views.py:

from django.shortcuts import render
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from rest_framework import status
from toys.models import Toy
from toys.serializers import ToySerializer


class JSONResponse(HttpResponse):
	"""JSON响应对象"""
    def __init__(self, data, **kwargs):
        content = JSONRenderer().render(data)
        kwargs['content_type'] = 'application/json'	#设置content_type内容协商类型为application/json
        super(JSONResponse, self).__init__(content, **kwargs)


@csrf_exempt	#允许视图进行跨域请求,不可用于生产环境
def toy_list(request):
    if request.method == 'GET':
        toys = Toy.objects.all()
        toys_serializer = ToySerializer(toys, many=True)	# 序列化。使用many = True参数创建ToyS​​erializer实例,以指定必须序列化多个实例而不仅仅是一个实例。
        return JSONResponse(toys_serializer.data)
    elif request.method == 'POST':
        toy_data = JSONParser().parse(request)	#先解析JSON数据
        toy_serializer = ToySerializer(data=toy_data)	# 反序列化。
        if toy_serializer.is_valid():
            toy_serializer.save()
            return JSONResponse(toy_serializer.data,
                                status=status.HTTP_201_CREATED)
        return JSONResponse(toy_serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)
    

@csrf_exempt
def toy_detail(request, pk):
    try:
        toy = Toy.objects.get(pk=pk)	#先检索数据对象是否向存在
    except Toy.DoesNotExist:
        return HttpResponse(status=status.HTTP_404_NOT_FOUND)
    if request.method == 'GET':
        toy_serializer = ToySerializer(toy)
        return JSONResponse(toy_serializer.data)
    elif request.method == 'PUT':
        toy_data = JSONParser().parse(request)
        toy_serializer = ToySerializer(toy, data=toy_data)	#更新,用新数据替换已存在的数据
        if toy_serializer.is_valid():
            toy_serializer.save()
            return JSONResponse(toy_serializer.data)
        return JSONResponse(toy_serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)
    elif request.method == 'DELETE':
        toy.delete()
        return HttpResponse(status=status.HTTP_204_NO_CONTENT)

代码思路比较明了:

  • toy_list函数列出所有toys或创建一个toy。它能够处理GETPOST方法。
  • toy_detail函数可检索、更新或删除现有某个toy。它能够处理GETPOSTDELETE方法。

3,定义URL路由

在toys项目urls.py中添加:

from django.conf.urls import url
from toys import views

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

在restful01\restful01\urls.py文件中添加:

from django.conf.urls import url, include

urlpatterns = [
    url(r'^', include('toys.urls')),
]
  • 这里将请求分发给toys应用的urls.py。

4,启动开发服务器

在与项目manage.py文件同级的目录中运行下面的命令:

python manage.py runserver

它将启动自带的开发服务器并默认监听127.0.0.1的8000端口。

127.0.0.1就是本地IP地址, 本机所在的LAN中的其他计算机是访问不了的,因此,如果想从其他计算机向我们的API发送HTTP请求,我们需要使用0.0.0.0::。这里假设使用IPv4,直接运行下面的命令就行:

python manage.py runserver 0.0.0.0:8000

也可以用你开发计算机所用的IP地址,比如:

python manage.py runserver 192.168.1.18:8000

5,使用GET获取实体资源集合

这里将使用curl工具来发送HTTP请求,到这里去下载,安装时记得要添加启动项到环境变量。

保持开发服务器是运行的,并打开一个命令行窗口,运行下面的命令:

curl -X GET localhost:8000/toys/

它发送了GET http://localhost:8000/toys/.这样的一条HTTP请求,这是最简单的能够被toys/views.py文件处理到的请求,结果就是返回序列化器序列化好了的所有JSON格式的Toy对象,如下所示:

[{"pk":3,"name":"Clash Royale play set","description":"6 figures from Clash Royale","release_date":"2017-10-09T12:10:00.776594Z","toy_category":"Playset","was_included_in_home":false},{"pk":2,"name":"Hawaiian Barbie","description":"Barbie loves Hawaii","release_date":"2021-06-12T00:05:48.517101Z","toy_category":"Dolls","was_included_in_home":true},{"pk":1,"name":"Snoopy talking action figure","description":"Snoopy speaks five languages","release_date":"2021-06-12T00:05:48.517101Z","toy_category":"Action figures","was_included_in_home":false}]

使用下面的命令还能额外查看HTTP的响应头:

curl -iX GET localhost:8000/toys/

结果如下:

HTTP/1.1 200 OK
Date: Fri, 11 Jun 2021 16:43:54 GMT
Server: WSGIServer/0.2 CPython/3.7.6
Content-Type: application/json
X-Frame-Options: SAMEORIGIN
Content-Length: 548

[{"pk":3,"name":"Clash Royale play set","description":"6 figures from Clash Royale","release_date":"2017-10-09T12:10:00.776594Z","toy_category":"Playset","was_included_in_home":false},{"pk":2,"name":"Hawaiian Barbie","description":"Barbie loves Hawaii","release_date":"2021-06-12T00:05:48.517101Z","toy_category":"Dolls","was_included_in_home":true},{"pk":1,"name":"Snoopy talking action figure","description":"Snoopy speaks five languages","release_date":"2021-06-12T00:05:48.517101Z","toy_category":"Action figures","was_included_in_home":false}]

回到服务器中,会发现有如下的一些信息:

......
[12/Jun/2021 00:43:54] "GET /toys/ HTTP/1.1" 200 548
......
  • 第一段是接受请求的时间
  • 第二段是HTTP请求方式
  • 第三段是请求的URI
  • 第四段是请求方式及协议版本
  • 第五段是响应状态码
  • 第六段是响应的长度

再回到命令行,会发现这里获得的JSON内容可读性不好,这需要更人性化的工具来提高可读性,比如使用httpie。这个工具提供了更简短的命令来发送HTTP请求,比如:

http :8000/toys/

结果如下:

HTTP/1.1 200 OK
Content-Length: 548
Content-Type: application/json
Date: Fri, 11 Jun 2021 17:04:22 GMT
Server: WSGIServer/0.2 CPython/3.7.6
X-Frame-Options: SAMEORIGIN

[
    {
        "description": "6 figures from Clash Royale",
        "name": "Clash Royale play set",
        "pk": 3,
        "release_date": "2017-10-09T12:10:00.776594Z",
        "toy_category": "Playset",
        "was_included_in_home": false
    },
    {
        "description": "Barbie loves Hawaii",
        "name": "Hawaiian Barbie",
        "pk": 2,
        "release_date": "2021-06-12T00:05:48.517101Z",
        "toy_category": "Dolls",
        "was_included_in_home": true
    },
    {
        "description": "Snoopy speaks five languages",
        "name": "Snoopy talking action figure",
        "pk": 1,
        "release_date": "2021-06-12T00:05:48.517101Z",
        "toy_category": "Action figures",
        "was_included_in_home": false
    }
]

明显可读性更高了。

也可以在命令中添加-b参数屏蔽响应头:

http -b :8000/toys/

6,使用GET获取单个实体资源

接下来我i们要查询单个toy实例,就像下面的命令一样:

http :8000/toys/3

这里不需要以”/“结尾,因为这不会在 toys/urls.py的urlpatterns中匹配到任何东西。上面的命令将匹配^toys/(?P<pk>[0-9]+)$并执行views.toy_detail函数,因为在URL的/toys/后会匹配一个参数,并将它作为pk传递给toy_detail函数。

结果如下:

HTTP/1.1 200 OK
Content-Length: 182
Content-Type: application/json
Date: Fri, 11 Jun 2021 17:06:02 GMT
Server: WSGIServer/0.2 CPython/3.7.6
X-Frame-Options: SAMEORIGIN

{
    "description": "6 figures from Clash Royale",
    "name": "Clash Royale play set",
    "pk": 3,
    "release_date": "2017-10-09T12:10:00.776594Z",
    "toy_category": "Playset",
    "was_included_in_home": false
}

如果我们访问一个不存在的pk,:

http :8000/toys/17500

结果就只会获得响应头,不会获得响应体:

HTTP/1.1 404 Not Found
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Fri, 11 Jun 2021 17:07:03 GMT
Server: WSGIServer/0.2 CPython/3.7.6
X-Frame-Options: SAMEORIGIN

7,使用POST

使用下面的命令通过 POST创建新的toy实例:

http POST :8000/toys/ name="PvZ 2 puzzle" description="Plants vs Zombies 2 puzzle" toy_category="Puzzle" was_included_in_home=false release_date="2017-10-08T01:01:00.776594Z"

这个HTTPpie命令将发送 POST http://localhost:8000/toys/,包含以下JSON格式的数据:
在这里插入图片描述
这个请求指定了/toys/,所以会匹配路由中的’^toys/$’从而执行views.toy_list函数。然后函数执行一个反序列化过程,将接收到的JSON数据转化为django模型类型并返回如下内容:

HTTP/1.1 201 Created
Content-Length: 171
Content-Type: application/json
Date: Fri, 11 Jun 2021 17:12:01 GMT
Server: WSGIServer/0.2 CPython/3.7.6
X-Frame-Options: SAMEORIGIN

{
    "description": "Plants vs Zombies 2 puzzle",
    "name": "PvZ 2 puzzle",
    "pk": 4,
    "release_date": "2017-10-08T01:01:00.776594Z",
    "toy_category": "Puzzle",
    "was_included_in_home": false
}

8,使用PUT

使用HTTPpie命令发送如下命令,将更新一条已存在的数据,否则将插入一条新数据:
在这里插入图片描述
在这里插入图片描述
同样的,上面的命令将匹配^toys/(?P<pk>[0-9]+)$并执行views.toy_detail函数并返回如下内容:
在这里插入图片描述
要注意的是,PUT请求应该包含一个toy实例应有的所有字段属性,不能漏,否则无法更新,因为PUT用于更新整个资源

如果要更新增量,则需要使用PATCH。虽然也可以用PUT,但对于这种指定的特殊任务,最好还是用PATCH。

9,使用DELETE

使用HTTPpie命令发送如下命令,将据pk值删除一条数据:

http DELETE :8000/toys/4

同样的,上面的命令将匹配^toys/(?P<pk>[0-9]+)$并执行views.toy_detail函数。

HTTP/1.1 204 No Content
Content-Length: 0
Content-Type: text/html; charset=utf-8
Date: Fri, 11 Jun 2021 17:15:14 GMT
Server: WSGIServer/0.2 CPython/3.7.6
X-Frame-Options: SAMEORIGIN

10,用Postman发送GET请求

先要安装Postman

用Postman软件来发送HTTP请求测试RESTful API,它不支持curl的命令,但我们上面用过的HTTPpie的命令都还能使用,用起来也更方便。

打开Postman,创建HTTP请求,请求方式选择GET,请求的URL填localhost:8000/toys/,点击发送,获得如下结果:
在这里插入图片描述
在这里插入图片描述

11, 用Postman发送POST请求

创建一个新HTTP请求标签,请求方式选择POST,请求的URL填localhost:8000/toys/,点击body中的raw填入如下内容:
在这里插入图片描述
点击与body同一排最后的Text,选择JSON。

点击发送请求,获得如下结果:
在这里插入图片描述
在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/98121.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!