如何在 Django REST Framework 中返回自定义 JSON?
在本文中,我们将创建基于类的视图,并将其与序列化器类相结合,为每个 HTTP 请求返回 JSON 表示。对于我们基于类的视图,我们将使用一组通用视图,这有助于实现最少行代码。
- 通用类和视图集
- 与关系资源交互的 HTTP 请求
通用类和视图集
我们将利用通用类视图来实现 get、post、delete、put 和 patch 方法。为此,我们需要利用两个 来自rest_framework.generics模块的通用类视图。他们是:
- 列表创建API视图
- RetrieveUpdateDestroyAPIView
ListCreateAPIView类视图实现了 get 方法(检索查询集列表)和 post 方法(创建模型实例)。并且, RetrieveUpdateDestroyAPIView类视图实现了 get(检索模型实例)、delete(删除模型实例)、put(完全更新模型实例)和 patch(部分更新模型实例)。
在 Django REST 框架中,这两个通用视图是作为 mixin 类实现的。该ListCreateAPIView使用ListModelMixin和CreateModelMixin从rest_framework.mixins从rest_framework.generics模块模块和GenericAPIView。我们来看看它的声明。
Python3
class ListCreateAPIView(mixins.ListModelMixin,
mixins.CreateModelMixin, GenericAPIView):
Python3
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
Python3
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'
Python3
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)
})
Python3
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[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[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[0-9]+)$',
views.RobotDetail.as_view(),
name=views.RobotDetail.name),
url(r'^$',
views.ApiRoot.as_view(),
name=views.ApiRoot.name),
]
Python3
from django.conf.urls import url, include
urlpatterns = [
url(r'^', include('robots.urls')),
]
所述RetrieveUpdateDestroyAPIView使用RetrieveModelMixin,UpdateModelMixin和DestroyModelMixin从rest_framework.mixins从rest_framework.generics模块模块和GenericAPIView。我们来看看它的声明。
蟒蛇3
class RetrieveUpdateDestroyAPIView(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
GenericAPIView):
现在,让我们回到 RESTFul Web 服务代码并创建所需的基于 Django 类的视图集。您可以打开restpi\robots\views.py Python文件并将其替换为以下代码。
蟒蛇3
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的子类。
蟒蛇3
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 Web 服务的根创建一个端点,便于浏览资源集合。此类中定义的 get 方法返回一个具有描述性名称及其 URL 的 Response 对象。在这里,它返回机器人类别列表、制造商列表和机器人列表的描述性名称和 URL。
接下来,我们需要在正则表达式中指定 URL 模式,以便为在views.py Python文件中定义的基于类的视图运行特定方法。客户端 HTTP 请求必须与此正则表达式匹配才能运行views.py文件中的方法。您可以在restapi/robots 中创建urls.py文件并添加以下代码。
蟒蛇3
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[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[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[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文件并将其替换为以下代码:
蟒蛇3
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=”Articulated Robots” notes=”Flexibility, dexterity, and reach make articulated robots ideally suited for tasks that span non-parallel planes”
输出:
让我们使用 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/
输出:
检索所有机器人类别
让我们编写一个 GET 请求来检索所有机器人类别。 HTTPie 命令是:
http :8000/robot-categories/
输出:
等效的 curl 命令是
curl -iX GET localhost:8000/robot-categories/
输出:
检索单个机器人类别
检索机器人类别的 HTTPie 命令是:
http :8000/robot-categories/1
输出:
等效的 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”
输出:
让我们编写一个 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/
输出:
让我们在 Robot 中添加更多条目。 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/
http :8000/robot-categories/
http :8000/manufacturers/
在机器人类别和制造商条目中,您可以注意到机器人在其 URL 形式中被提及。
PUT、PATCH 和 DELETE 资源
现在让我们编写 PUT、PATCH 和 DELETE 请求。我们将添加一个新的机器人类别(Test Category)和制造商(Test Manufacturer)。 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 动词
现在让我们使用PUT HTTP 动词来编辑名为 TEST 3 的最后一个条目,它的主键是 11。
HTTPUtility Pie 命令是:
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
补丁 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
删除 HTTP 动词
现在,让我们使用DELETE HTTP Verb 删除具有主键 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 个属于测试类别的机器人(测试 1、测试 2 和测试 3 )。已使用删除请求删除了主 ID 为 11(测试 3 )的机器人。数据库中存在主 ID 为 9(测试 1)和 10(测试 2)的其余两个机器人。由于我们删除了测试类别,其他两个机器人将自动从表中清除。让我们使用 psql 命令检查数据库。
select * from robots_robot;
输出:
您可以注意到,属于测试类别的机器人已成功清除。这在代码on_delete=models.CASCADE的帮助下成为可能,在将机器人类别定义为机器人模型中的外键时提到。
概括
在本文中,我们学习了实现 HTTP 请求的通用类视图。为此,我们使用了来自 rest_framework.generics 模块的两个通用类视图ListCreateAPIView和RetrieveUpdateDestroyAPIView 。我们还编写了不同的 HTTP 请求来与相关资源进行交互。