1,理解Django是如何工作的
当Django服务器接收到HTTP请求时,Django创建一个django.http.HttpRequest对象。该对象的实例包含有关请求的元数据,其中就包含HTTP动作,例如GET
,POST
或PUT
,可通过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参数创建ToySerializer实例,以指定必须序列化多个实例而不仅仅是一个实例。
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。它能够处理
GET
与POST
方法。 - toy_detail函数可检索、更新或删除现有某个toy。它能够处理
GET
、POST
与DELETE
方法。
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