如何在Django REST框架中返回自定义JSON?
在这篇文章中,我们将创建基于类的视图,并将其与序列化器类相结合,为每个HTTP请求返回JSON表示。对于我们的基于类的视图,我们将使用一组通用的视图,这有助于实现最小的代码行。
- 通用类和视图集
- 与关系资源互动的HTTP请求
通用类和视图集
我们将利用通用类视图来实现get、post、delete、put和patch方法。为此,我们需要利用rest_framework.generics模块中的两个__泛型类视图。它们是
- ListCreateAPIView
- RetrieveUpdateDestroyAPIView
ListCreateAPIView类视图实现了get方法(检索一个queryset的列表)和post方法(创建一个模型实例)。而且,RetrieveUpdateDestroyAPIView类视图实现了get(检索一个模型实例),delete(删除一个模型实例),put(完全更新一个模型实例)和patch(部分更新一个模型实例)。
在Django REST框架中,这两个通用视图被实现为混合类。ListCreateAPIView使用了来自rest_framework.mixins模块的ListModelMixin和CreateModelMixin以及来自rest_framework.generics模块的_GenericAPIView。我们来看看它的声明。
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin, GenericAPIView):
RetrieveUpdateDestroyAPIView使用了来自rest_framework.mixins模块的RetrieveModelMixin、UpdateModelMixin和DestroyModelMixin以及来自rest_framework.enerics模块的_GenericAPIView。我们来看看它的声明。
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
现在,让我们回到我们的RESTFul网络服务代码,创建所需的一组基于Django类的视图。你可以打开restpi\robots\views.py Python文件,用下面的代码替换它。
from django.shortcuts import render
from rest_framework import generics
from rest_framework.response import Response
from rest_framework.reverse import reverse
from robots.models import RobotCategory
from robots.models import Manufacturer
from robots.models import Robot
from robots.serializers import RobotCategorySerializer
from robots.serializers import ManufacturerSerializer
from robots.serializers import RobotSerializer
class ApiRoot(generics.GenericAPIView):
name = 'api-root'
def get(self, request, *args, **kwargs):
return Response({
'robot-categories': reverse(RobotCategoryList.name, request=request),
'manufacturers': reverse(ManufacturerList.name, request=request),
'robots': reverse(RobotList.name, request=request)
})
class RobotCategoryList(generics.ListCreateAPIView):
queryset = RobotCategory.objects.all()
serializer_class = RobotCategorySerializer
class RobotCategoryDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = RobotCategory.objects.all()
serializer_class = RobotCategorySerializer
name = 'robotcategory-detail'
class ManufacturerList(generics.ListCreateAPIView):
queryset = Manufacturer.objects.all()
serializer_class = ManufacturerSerializer
name = 'manufacturer-list'
class ManufacturerDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Manufacturer.objects.all()
serializer_class = ManufacturerSerializer
name = 'manufacturer-detail'
class RobotList(generics.ListCreateAPIView):
queryset = Robot.objects.all()
serializer_class = RobotSerializer
name = 'robot-list'
class RobotDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Robot.objects.all()
serializer_class = RobotSerializer
name = 'robot-detail'
这里的RobotCategoryList、ManufacturerList和RobotList是generics.ListCreateAPIView的子类;RobotCategoryDetail、ManufacturerDetail和RobotDetail是generics.RetrieveUpdateDestroyAPIView的子类。每个子类有一个_queryset属性、serializer_class属性和一个name属性。queryset属性存储了所有被检索的对象,serializer_class属性存储了序列化器类,而name属性则用来识别每个视图。
除了基于类的视图,你可以注意到一个ApiRoot类,它是rest_framework.generics.GenericAPIView的一个子类。
class ApiRoot(generics.GenericAPIView):
name = 'api-root'
def get(self, request, *args, **kwargs):
return Response({
'robot-categories': reverse(RobotCategoryList.name, request=request),
'manufacturers': reverse(ManufacturerList.name, request=request),
'robots': reverse(RobotList.name, request=request)
})
ApiRoot类为我们的RESTful网络服务的根创建了一个端点,以方便浏览资源集合。这个类中定义的获取方法会返回一个具有描述性名称和URL的响应对象。这里,它返回机器人类别列表、制造商列表和机器人列表的描述性名称和URL。
接下来,我们需要在正则表达式中指定URL模式,以运行views.py Python文件中定义的基于类的视图的特定方法。客户端HTTP请求必须与这个正则表达式相匹配,以运行views.py文件中的方法。你可以在restapi/robots中创建urls.py文件并添加以下代码。
from django.conf.urls import url
from robots import views
urlpatterns = [
url(r'^robot-categories/',
views.RobotCategoryList.as_view(),
name=views.RobotCategoryList.name),
url(r'^robot-categories/(?P<pk>[0-9]+)',
views.RobotCategoryDetail.as_view(),
name=views.RobotCategoryDetail.name),
url(r'^manufacturers/',
views.ManufacturerList.as_view(),
name=views.ManufacturerList.name),
url(r'^manufacturers/(?P<pk>[0-9]+)',
views.ManufacturerDetail.as_view(),
name=views.ManufacturerDetail.name),
url(r'^robots/',
views.RobotList.as_view(),
name=views.RobotList.name),
url(r'^robots/(?P<pk>[0-9]+)',
views.RobotDetail.as_view(),
name=views.RobotDetail.name),
url(r'^$',
views.ApiRoot.as_view(),
name=views.ApiRoot.name),
]
作为最后一步,我们需要定义根URL的配置。你可以打开restapi/restapi/urls.py Python文件,用下面的代码替换它。
from django.conf.urls import url, include
urlpatterns = [
url(r'^', include('robots.urls')),
]
与资源互动的HTTP请求
现在是时候通过组成和发送各种HTTP请求来测试我们的代码了。在这里,我们将同时利用HTTPie命令和CURL命令。
创建一个新的机器人类别
让我们编写并发送一个HTTP Post请求来创建一个新的机器人类别。HTTPie的命令是。
http POST :8000/robot-categories/ name=”关节型机器人” notes=”灵活性、灵巧性和伸展性使关节型机器人非常适用于跨越非平行平面的任务”
输出:
机器人类别发布请求(HTTPie)。
让我们使用curl命令创建另一个机器人类别。
curl -iX POST -H “Content-Type: application/json” -d “{\”name\”:\”SCARA Robots\”, \”notes\”:\”A Selective Compliance Articulated Robot Arm (SCARA) is a good and cost-effective choice for performing operations between two parallel planes\”}” localhost:8000/robot-categories/
输出:
机器人分类POST请求(cURL)
检索所有机器人类别
让我们编写一个GET请求来检索所有的机器人类别。HTTPie的命令是。
http :8000/robot-categories/
输出:
机器人类别的GET请求(HTTPie实用命令)。
相等的curl命令是
curl -iX GET localhost:8000/robot-categories/
输出:
GET request (cURL)
检索单个机器人类别
检索机器人类别的HTTPie命令是。
http :8000/robot-categories/1
输出:
GET request (single category)
相等的curl命令是。
curl -iX GET localhost:8000/robot-categories/1
创建一个新的制造商
让我们编写并发送一个HTTP POST请求来创建一个制造商。HTTPie的命令是。
http :8000/manufacturers/ name=”FANUC Global” rating=4 notes=”The automation specialist and industrial robot manufacturer”
输出:
HTTP/1.1 201 Created
Allow: GET, POST, HEAD, OPTIONS
Content-Length: 219
Content-Type: application/json
Date: Mon, 16 Nov 2020 06:36:12 GMT
Location: http://localhost:8000/manufacturers/1
Referrer-Policy: same-origin
Server: WSGIServer/0.2 CPython/3.7.5
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
{
“entry_date”: “2020-11-16T06:36:12.449074Z”,
“robots”: [],
“name”: “FANUC Global”,
“notes”: “The automation specialist and industrial robot manufacturer”,
“pk”: 1,
“rating”: 4,
“url”: “http://localhost:8000/manufacturers/1”
}
让我们使用curl命令创建另一个制造商。
curl -iX POST -H “Content-Type: application/json” -d “{\”name\”:\”ABB\”, \”rating\”:5, \”notes\”:\”Focused in Electrification, Industrial Automation, Robotics, Discrete Automation and Motion\”}” localhost:8000/manufacturers/
输出:
HTTP/1.1 201 Created
Date: Mon, 16 Nov 2020 06:49:43 GMT
Server: WSGIServer/0.2 CPython/3.7.5
Content-Type: application/json
Location: http://localhost:8000/manufacturers/2
Vary: Accept, Cookie
Allow: GET, POST, HEAD, OPTIONS
X-Frame-Options: DENY
Content-Length: 242
X-Content-Type-Options: nosniff
Referrer-Policy: same-origin
{“url”:”http://localhost:8000/manufacturers/2″,”pk”:2,”name”:”ABB”,”rating”:5,
“notes”:”Focused in Electrification, Industrial Automation, Robotics, Discrete Automation
and Motion”,”entry_date”:”2020-11-16T06:49:43.108992Z”,”robots”:[]}
找回一个制造商
让我们编写一个请求来检索一个制造商。HTTPie的命令是。
http :8000/manufacturers/2
输出:
检索单个制造商
相等的curl命令是。
curl -iX GET localhost:8000/manufacturers/2
添加机器人细节
我们已经填充了机器人类别和制造商的详细信息。现在,让我们编写并发送一个POST请求来添加机器人的详细信息。HTTPie的命令是
http POST :8000/robots/ name=”FANUC M-710ic/50″ robot_category=”Articulated Robots” currency=”USD” price=37000 manufacturer=”FANUC Global” manufacturing_date=”2019-10-12 00:00:00.000000+00:00″ add_details=”Axes 6, Payload 50 KG, Reach 2050 MM”
输出:
Robot Entry (HTTP Utility Pie command)
让我们编写一条curl命令来创建一个新条目。
curl -iX POST -H “Content-Type: application/json” -d “{\”name\”:\”SR-3iA\”, \”robot_category\”:\”SCARA Robots\”, \”currency\”:\”USD\”, \”price\”:37000, \”manufacturer\”:\”FANUC Global\”, \”manufacturing_date\”:\”2019-10-12 00:00:00.000000+00:00\”, \”add_details\”:\”Axis 4, Payload 3 KG, Reach 400 MM\”}” localhost:8000/robots/
输出:
让我们在机器人中增加一些条目。HTTPie的命令是。
http POST :8000/robots/ name=”IRB 120″ robot_category=”Articulated Robots” currency=”USD” price=14500 manufacturer=”ABB” manufacturing_date=”2020-05-10 00:00:00.000000+00:00″ add_details=”Axes 6, Payload 3 KG, Reach 0.58m”
http POST :8000/robots/ name=”IRB 910SC” robot_category=”SCARA Robots” currency=”USD” price=25000 manufacturer=”ABB” manufacturing_date=”2020-05-10 00:00:00.000000+00:00″ add_details=”Axes 4, Payload 6 KG, Reach 0.65m”
我们来看看机器人、机器人类别和制造商名单。
http :8000/robots/
Robot List
http :8000/robot-categories/
机器人类别列表
http :8000/manufacturers/
Manufacturer List
在机器人类别和制造商条目中,你可以注意到,机器人是以其URL形式提到的。
PUT, PATCH, and DELETE资源
现在我们来编写PUT、PATCH和DELETE请求。我们将添加一个新的机器人类别(测试类别)和制造商(测试制造商)。HTTPie的命令如下。
http POST :8000/robot-categories/ name=”Test Category” notes=”Test”
http POST :8000/manufacturers/ name=”Test Manufacturer” rating=1 notes=”Test”
让我们添加一些属于测试类别和测试制造商的机器人。HTTPie命令如下。
http POST :8000/robots/ name=”TEST 1″ robot_category=”Test Category” currency=”USD” price=37000 manufacturer=”Test Manufacturer” manufacturing_date=”2019-10-12 00:00:00.000000+00:00″ add_details=”Test”
http POST :8000/robots/ name=”TEST 2″ robot_category=”Test Category” currency=”USD” price=37000 manufacturer=”Test Manufacturer” manufacturing_date=”2019-10-12 00:00:00.000000+00:00″ add_details=”Test”
http POST :8000/robots/ name=”TEST 3″ robot_category=”Test Category” currency=”USD” price=37000 manufacturer=”Test Manufacturer” manufacturing_date=”2019-10-12 00:00:00.000000+00:00″ add_details=”Test”
让我们用下面的psql命令检查数据库中的条目。
select * from robots_robot;
输出:
你可以注意到,新的条目被添加到我们的数据库。
PUT HTTP verb
现在,让我们使用PUT HTTP动词编辑最后一个名为TEST 3的条目,它的主键是11,。
HTTPUtility派的命令是。
http PUT :8000/robots/11 name=”TEST 3″ robot_category=”Test Category” currency=”USD” price=12000 manufacturer=”Test Manufacturer” manufacturing_date=”2020-10-12 00:00:00.000000+00:00″ add_details=”Test3″
输出:
相等的curl命令是
curl -iX PUT -H “Content-Type: application/json” -d “{\”name\”:\”TEST 3\”, \”robot_category\”:\”Test Category\”, \”currency\”:\”USD\”, \”price\”:12000, \”manufacturer\”:\”Test Manufacturer\”, \”manufacturing_date\”:\”2020-10-12 00:00:00.000000+00:00\”, \”add_details\”:\”Test3\”}” localhost:8000/robots/11
PATCH HTTP动词
让我们部分地编辑有主键11的资源。PATCH请求的HTTPie命令是。
http PATCH :8000/robots/11 price=15000 add_details=”Test3 Patch”
输出:
相等的curl命令是。
curl -iX PATCH -H “Content-Type: application/json” -d “{ \”price\”:15000, \”add_details\”:\”Test3 Patch\”}” localhost:8000/robots/11
DELETE HTTP动词
现在,让我们使用DELETE HTTP动词删除有主键11的条目。HTTPie命令是。
http DELETE :8000/robots/11
输出:
相等的curl命令是
curl -iX DELETE localhost:8000/robots/11
现在,我们需要检查如果一个机器人类别被删除会发生什么。根据我们的代码,如果一个类别被删除,那么所有属于这个特定类别的机器人也应该被清除掉。让我们删除我们的测试类别(主ID 3)。HTTPie的命令是
http DELETE :8000/robot-categories/3
输出:
让我们看一下机器人表。我们总共添加了3个机器人(Test 1, Test 2, and Test 3),它们属于Test Category。主标识为11的机器人(测试3)已经通过删除请求被删除。其余两个机器人的主标识为9(测试1)和10(测试2),存在于数据库中。由于我们删除了测试类别,其他两个机器人将被自动从表中清除。让我们用psql命令检查一下数据库。
select * from robots_robot;
输出:
你可以注意到,属于测试类别的机器人被成功清除了。这是借助于代码on_delete=models.CASCADE,在机器人模型中定义机器人类别为外键时提到的。
总结
在这篇文章中,我们学习了通用类视图来实现HTTP请求。为此,我们使用了rest_framework.generics模块中的两个通用类视图,_ListCreateAPIView _和_RetrieveUpdateDestroyAPIView _。而且我们还组成了不同的HTTP请求来与相关资源进行交互。