📌  相关文章
📜  Django REST Framework 中的可浏览 API

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

Django REST Framework 中的可浏览 API

Django REST 框架中的可浏览 API 功能为不同的资源生成 HTML 输出。它有助于通过任何 Web 浏览器与 RESTful Web 服务进行交互。要启用此功能,我们应该为请求标头中的 Content-Type 键指定 text/html。它帮助我们使用 Web 浏览器浏览 API 并可以发出不同的 HTTP 请求。在本节中,我们将使用 Django REST API 框架中的可浏览 API 功能。

创建一个简单的项目来演示可浏览的 API——

让我们创建应用程序机器人所需的模型、序列化程序和视图。

创建模型

在 Django 中,模型是以面向对象的方式处理数据库的类。每个模型类引用一个数据库表,模型类中的每个属性引用一个数据库列。在这里,我们将创建以下模型:

  • RobotCategory(机器人类别)
  • 制造商(制造商详细信息)
  • 机器人(机器人详情)

RobotCategory 模型需要:



  • 机器人类别名称

制造商模型要求:

  • 生产商名称

机器人模型需要:

  • 机器人名称
  • RobotCategory 模型的外键
  • 制造商模型的外键
  • 货币
  • 价钱
  • 生产日期

让我们看看我们的机器人 Restful Web 服务中的 HTTP 动词、范围语义。

HTTP VerbScopeSemanticsURL
GETRobot CategoryRetrieve a Robot Categoryhttp://localhost:8000/robocategory/{id}/
GETCollection of Robot CategoryRetrieve all Robot Category in the collectionhttp://localhost:8000/robocategory/
POSTCollection of Robot CategoryCreate a new Robot Category in the collectionhttp://localhost:8000/robocategory/{id}/
PUTRobot CategoryUpdate a Robot Categoryhttp://localhost:8000/robocategory/{id}/
DELETERobot CategoryDelete a Robot Categoryhttp://localhost:8000/robocategory/{id}/
GETManufacturerRetrieve a Manufacturer http://localhost:8000/manufacturer/{id}/
GETCollection of ManufacturerRetrieve all Manufacturer in the collectionhttp://localhost:8000/manufacturer/
POSTCollection of ManufacturerCreate a Manufacturer in the collectionhttp://localhost:8000/manufacturer/{id}/
PUTManufacturerUpdate a Manufacturerhttp://localhost:8000/manufacturer/{id}/
DELETEManufacturerDelete a Manufacturerhttp://localhost:8000/manufacturer/{id}/
GETRobotRetrieve a Robothttp://localhost:8000/robot/{id}/
GETCollection of RobotRetrieve all Robot in the collectionhttp://localhost:8000/robot/
POSTCollection of RobotCreate a Robot in the collectionhttp://localhost:8000/robot/{id}/
PUTRobotUpdate a Robothttp://localhost:8000/robot/{id}/
DELETERobotDelete a Robothttp://localhost:8000/robot/{id}/

让我们为机器人类别、制造商、机器人及其关系创建模型。您可以在 models.py 文件中添加以下代码。

Python3
from django.db import models
  
class RobotCategory(models.Model):
    name = models.CharField(max_length=150, unique=True)
  
    class Meta:
        ordering = ('name',)
  
    def __str__(self):
        return self.name
  
class Manufacturer(models.Model):
    name = models.CharField(max_length=150, unique=True)
  
    class Meta:
        ordering = ('name',)
  
    def __str__(self):
        return self.name
  
class Robot(models.Model):
    CURRENCY_CHOICES = (
        ('INR', 'Indian Rupee'),
        ('USD', 'US Dollar'),
        ('EUR', 'Euro'),
    )
  
    name = models.CharField(max_length=150, unique=True)
    robot_category = models.ForeignKey(
        RobotCategory,
        related_name='robots',
        on_delete=models.CASCADE)
    manufacturer = models.ForeignKey(
        Manufacturer,
        related_name='robots',
        on_delete=models.CASCADE)
    currency = models.CharField(
        max_length=3,
        choices= CURRENCY_CHOICES,
        default='INR')
    price = models.IntegerField()
    manufacturing_date = models.DateTimeField()
  
    class Meta:
        ordering = ('name',)
  
    def __str__(self):
        return self.name


Python3
from rest_framework import serializers
from robots.models import RobotCategory, Manufacturer, Robot
  
class RobotCategorySerializer(serializers.HyperlinkedModelSerializer):
    robots = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='robot-detail')
  
    class Meta:
        model = RobotCategory
        fields = '__all__'
  
  
class ManufacturerSerializer(serializers.HyperlinkedModelSerializer):
    robots = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='robot-detail')
  
    class Meta:
        model = Manufacturer
        fields = '__all__'
  
class RobotSerializer(serializers.HyperlinkedModelSerializer):
    robot_category = serializers.SlugRelatedField(
        queryset=RobotCategory.objects.all(), slug_field='name')
    manufacturer = serializers.SlugRelatedField(
        queryset=Manufacturer.objects.all(), slug_field='name')
    currency = serializers.ChoiceField(
        choices=Robot.CURRENCY_CHOICES)
    currency_name = serializers.CharField(
        source='get_currency_display',
        read_only=True)
  
    class Meta:
        model = Robot
        fields = '__all__'


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, Manufacturer, Robot
from robots.serializers import RobotCategorySerializer, \
     ManufacturerSerializer, 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
    name = 'robotcategory-list'
  
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
from django.urls import path
from robots import views
  
urlpatterns = [
    path('robocategory/',
         views.RobotCategoryList.as_view(),
         name='robotcategory-list'),
    path('robocategory//',
         views.RobotCategoryDetail.as_view(),
         name='robotcategory-detail'),
    path('manufacturer/',
         views.ManufacturerList.as_view(),
         name='manufacturer-list'),
    path('manufacturer//',
         views.ManufacturerDetail.as_view(),
         name='manufacturer-detail'),
    path('robot/',
         views.RobotList.as_view(),
         name='robot-list'),
    path('robot//',
         views.RobotDetail.as_view(),
         name='robot-detail'),
    path('',
        views.ApiRoot.as_view(),
        name=views.ApiRoot.name)
]


Python3
from django.contrib import admin
from django.urls import path, include
  
urlpatterns = [
    path('', include('robots.urls')),
]


这里我们有三个类,它们是 django.db.models.Model 类的子类:

  • 机器人类别
  • 制造商
  • 机器人

Robot 类与 RobotCategory 模型和制造商模型保持多对一的关系。这种关系是通过使用 django.db.models.ForeignKey 类来实现的。代码如下:

robot_category = models.ForeignKey(
        RobotCategory,
        related_name='robots',
        on_delete=models.CASCADE)
    manufacturer = models.ForeignKey(
        Manufacturer,
        related_name='robots',
        on_delete=models.CASCADE)

related_name 参数创建反向关系。此处related_name 中的值“robots”创建了从RobotCategory 到Robot 和Manufacturer 到Robot 的反向关系。这有助于获取属于机器人类别并基于制造商的所有机器人。



接下来,您可以执行迁移过程并应用所有生成的迁移。您可以使用以下命令

创建序列化程序

现在,我们需要序列化 RobotCategory、Manufacturer 和 Robot 实例。在这里,我们将使用 HyperlinkedModelSerializer 来处理模型关系。您可以查看 DRF Serializer Relations 主题以详细了解。

蟒蛇3

from rest_framework import serializers
from robots.models import RobotCategory, Manufacturer, Robot
  
class RobotCategorySerializer(serializers.HyperlinkedModelSerializer):
    robots = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='robot-detail')
  
    class Meta:
        model = RobotCategory
        fields = '__all__'
  
  
class ManufacturerSerializer(serializers.HyperlinkedModelSerializer):
    robots = serializers.HyperlinkedRelatedField(
        many=True,
        read_only=True,
        view_name='robot-detail')
  
    class Meta:
        model = Manufacturer
        fields = '__all__'
  
class RobotSerializer(serializers.HyperlinkedModelSerializer):
    robot_category = serializers.SlugRelatedField(
        queryset=RobotCategory.objects.all(), slug_field='name')
    manufacturer = serializers.SlugRelatedField(
        queryset=Manufacturer.objects.all(), slug_field='name')
    currency = serializers.ChoiceField(
        choices=Robot.CURRENCY_CHOICES)
    currency_name = serializers.CharField(
        source='get_currency_display',
        read_only=True)
  
    class Meta:
        model = Robot
        fields = '__all__'

RobotCategorySerializer 和ManufacturerSerializer 类是HyperlinkedModelSerializer 类的子类,反向关系(RobotCategory 到Robot 和Manufacturer 到Robot)使用HyperlinkedRelatedField 表示,其中许多和read_only 属性设置为True。 view_name —robot-detail — 允许可浏览的 API 功能为用户提供点击工具,以呈现超链接。

RobotSerializer 类也是 HyperlinkedModelSerializer 类的子类。 RobotSerializer 类声明了两个属性——robot_category 和制造商——它们保存了一个 serializers.SlugRelatedField 的实例。 SlugRelated Field 通过唯一的 slug 属性表示关系。

创建视图

让我们利用 Django REST Framework 提供的基于类的通用视图来处理 HTTP 请求并提供适当的 HTTP 响应。您可以查看基于 DRF 类的视图以获取详细说明。

蟒蛇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, Manufacturer, Robot
from robots.serializers import RobotCategorySerializer, \
     ManufacturerSerializer, 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
    name = 'robotcategory-list'
  
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'

在这里,我们的视图类从 rest_framework.generics 导入,我们利用了两个基于类的通用视图——ListCreateAPIView 和 RetrieveUpdateDestroyAPIView。



您可以注意到 ApiRoot 类是generics.GenericAPIView的子类它为我们的 Web 服务的根创建了一个端点。它使用可浏览的 API 功能方便浏览资源。

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)
            })    

get 方法返回一个 Response 对象(作为字符串的键/值对),该对象具有视图的描述性名称及其 URL。

设置 URL Conf

转到应用程序(机器人)文件夹并创建一个名为 urls.py 的新文件。您可以添加以下代码:

蟒蛇3

from django.urls import path
from robots import views
  
urlpatterns = [
    path('robocategory/',
         views.RobotCategoryList.as_view(),
         name='robotcategory-list'),
    path('robocategory//',
         views.RobotCategoryDetail.as_view(),
         name='robotcategory-detail'),
    path('manufacturer/',
         views.ManufacturerList.as_view(),
         name='manufacturer-list'),
    path('manufacturer//',
         views.ManufacturerDetail.as_view(),
         name='manufacturer-detail'),
    path('robot/',
         views.RobotList.as_view(),
         name='robot-list'),
    path('robot//',
         views.RobotDetail.as_view(),
         name='robot-detail'),
    path('',
        views.ApiRoot.as_view(),
        name=views.ApiRoot.name)
]

它定义了必须在请求中匹配的 URL 模式,以便为 views.py 文件中定义的基于类的视图执行特定方法。现在我们必须设置根 URL 配置。您可以添加以下代码:

蟒蛇3

from django.contrib import admin
from django.urls import path, include
  
urlpatterns = [
    path('', include('robots.urls')),
]

如何使用可浏览 API 向 API 发出请求?

让我们编写并发送 HTTP 请求以在响应中生成 text/html 内容。 RESTFul Web 服务使用 BrowsableAPIRenderer 类来生成 HTML 内容。接受 text/html 的 HTTPie 命令如下:

分享命令提示符截图供大家参考



在使用可浏览 API 之前,让我们使用 HTTPie 命令为机器人类别、制造商和机器人创建一个新条目。命令如下:

获取 HTTP 请求

现在,让我们使用浏览器浏览“机器人”Restful Web 服务。您可以使用以下网址。

分享浏览器截图供大家参考

您可以点击机器人类别、制造商和机器人对应的链接并查看数据。分享显示robots结果的浏览器截图(http://localhost:8000/robot/)

POST HTTP 请求

接下来,让我们创建一个新的机器人类别。您可以浏览以下链接并向下滚动。

分享浏览器截图供大家参考

您可以键入新机器人类别的名称,然后单击 POST 按钮。在这里,它以 HTML 形式显示。如果您选择原始数据,请选择媒体类型为 application/json,将新的机器人类别名称填充到名称字段,然后单击 POST 按钮。分享截图供大家参考。

分享输出截图

让我们创建一个新的制造商,您可以浏览以下网址

分享浏览器截图

您可以输入制造商名称 (ABB) 并单击 POST 按钮。浏览器显示输出如下图

最后,让我们为机器人创建一个新条目。您可以浏览以下网址并向下滚动。

让我们填充数据。分享浏览器截图供大家参考

在这里,您可以注意到机器人类别、制造和货币是下拉字段。填充条目后,您可以单击 POST 按钮。在显示输出的屏幕截图下方共享。

PUT HTTP 请求

让我们编辑 pk 值为 2 的机器人的价格。您可以浏览以下 URL 并向下滚动。

分享浏览器截图。您可以将价格更改为 27000,然后单击 PUT 按钮。

分享输出的截图。

删除 HTTP 请求

您可以创建一个新的测试条目并使用 pk 值浏览 URL。

您会注意到一个 DELETE 按钮。下面分享浏览器截图:

单击“删除”按钮时,浏览器会确认相同。您可以单击确认窗口中的删除按钮。下面分享截图。

如果删除成功,则会显示以下输出。

让我们总结一下

通过本节,我们了解了如何使用 Django REST API 框架中的可浏览 API 功能。我们编写并发送了生成文本/html 内容作为响应的 HTTP 请求,并在 Web 浏览器中分析了响应。