📌  相关文章
📜  如何在 Django REST Framework 中返回自定义 JSON?

📅  最后修改于: 2022-05-13 01:55:44.275000             🧑  作者: Mango

如何在 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使用ListModelMixinCreateModelMixinrest_framework.mixinsrest_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,UpdateModelMixinDestroyModelMixinrest_framework.mixinsrest_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'

这里的RobotCategoryListManufacturerListRobotListgenerics.ListCreateAPIView的子类; RobotCategoryDetailManufacturerDetailRobotDetailgenerics.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 命令是:

输出:

机器人类别发布请求 (HTTPie)

让我们使用 curl 命令创建另一个机器人类别。

输出:

机器人类别 POST 请求 (cURL)

检索所有机器人类别

让我们编写一个 GET 请求来检索所有机器人类别。 HTTPie 命令是:

输出:

机器人类别 GET 请求(HTTPie 实用程序命令)

等效的 curl 命令是

输出:

GET 请求(卷曲)

检索单个机器人类别

检索机器人类别的 HTTPie 命令是:

输出:

GET 请求(单一类别)

等效的 curl 命令是:

创建一个新的制造商

让我们编写并发送一个 HTTP POST 请求来创建一个制造商。 HTTPie 命令是:

输出:

让我们使用 curl 命令创建另一个制造商。

输出:

检索制造商

让我们编写一个检索制造商的请求。 HTTPie 命令是:

输出:

检索单个制造商

等效的 curl 命令是:

添加机器人详细信息

我们已经填充了机器人类别和制造商详细信息。现在,让我们编写并发送 POST 请求以添加机器人详细信息。 HTTPie 命令是

输出:

机器人入口(HTTP Utility Pie 命令)

让我们编写一个 curl 命令来创建一个新条目。

输出:

让我们在 Robot 中添加更多条目。 HTTPie 命令是:

让我们看看机器人、机器人类别和制造商列表。

机器人列表

机器人类别列表

制造商列表

在机器人类别和制造商条目中,您可以注意到机器人在其 URL 形式中被提及。

PUT、PATCH 和 DELETE 资源

现在让我们编写 PUT、PATCH 和 DELETE 请求。我们将添加一个新的机器人类别(Test Category)和制造商(Test Manufacturer)。 HTTPie 命令如下:

让我们添加一些属于测试类别测试制造商的机器人。 HTTPie 命令如下:

让我们使用以下 psql 命令检查数据库中的条目。

输出:

您可以注意到我们的数据库中添加了新条目。

PUT HTTP 动词

现在让我们使用PUT HTTP 动词来编辑名为 TEST 3 的最后一个条目,它的主键是 11。

HTTPUtility Pie 命令是:

输出:



等效的 curl 命令是

补丁 HTTP 动词

让我们部分编辑具有主键 11 的资源。 PATCH请求的 HTTPie 命令是:

输出:

等效的 curl 命令是:

删除 HTTP 动词

现在,让我们使用DELETE HTTP Verb 删除具有主键 11 的条目。 HTTPie 命令是:

输出:

等效的 curl 命令是

现在,我们需要检查如果删除机器人类别会发生什么。根据我们的代码,如果一个类别被删除,那么所有属于该特定类别的机器人也应该被清除。让我们删除我们的测试类别(主 ID 3)。 HTTPie 命令是

输出:

我们来看看机器人桌。我们总共添加了 3 个属于测试类别的机器人(测试 1、测试 2 和测试 3 )。已使用删除请求删除了主 ID 为 11(测试 3 )的机器人。数据库中存在主 ID 为 9(测试 1)和 10(测试 2)的其余两个机器人。由于我们删除了测试类别,其他两个机器人将自动从表中清除。让我们使用 psql 命令检查数据库。

输出:

您可以注意到,属于测试类别的机器人已成功清除。这在代码on_delete=models.CASCADE的帮助下成为可能,在将机器人类别定义为机器人模型中的外键时提到。

概括

在本文中,我们学习了实现 HTTP 请求的通用类视图。为此,我们使用了来自 rest_framework.generics 模块的两个通用类视图ListCreateAPIViewRetrieveUpdateDestroyAPIView 。我们还编写了不同的 HTTP 请求来与相关资源进行交互。