Django REST framework - 模式

模式

机器可读的[模式]描述了通过API可用的资源、它们的URL、它们的表示方式以及它们支持的操作。

— Heroku,Heroku平台API的JSON模式


弃用通知:

REST framework内置的用于生成OpenAPI模式的支持已被弃用,转而支持第三方包来提供此功能。内置支持将被移到一个单独的包中,然后在后续版本中逐步淘汰。

作为一个完整的替代方案,我们推荐drf-spectacular包。它广泛支持从REST framework API生成OpenAPI 3模式,同时提供自动和可定制的选项。有关详细信息,请参阅文档你的API。


API模式是一个有用的工具,允许多种使用场景,包括生成参考文档,或驱动可以与你的API交互的动态客户端库。

Django REST Framework提供了自动生成OpenAPI模式的支持。

概览

模式生成有多个活动部分。概览如下:

  • SchemaGenerator 是一个顶级类,负责遍历你配置的URL模式,查找 APIView 子类,询问它们的模式表示,并编译最终的模式对象。
  • AutoSchema 封装了每个视图模式内省所需的所有详细信息。通过 schema 属性附加到每个视图上。你可以通过子类化 AutoSchema 来自定义你的模式。
  • generateschema 管理命令允许你离线生成静态模式。
  • 另外,你可以路由 SchemaView 来动态生成和提供你的模式。
  • settings.DEFAULT_SCHEMA_CLASS 允许你指定一个 AutoSchema 子类作为你的项目的默认模式。

以下部分将进行更详细的解释。

生成OpenAPI模式

安装依赖项

pip install pyyaml uritemplate inflection
  • pyyaml 用于将模式生成为基于YAML的OpenAPI格式。
  • uritemplate 用于内部获取路径中的参数。
  • inflection 用于在列表端点中更适当地复数化操作。

使用 generateschema 管理命令生成静态模式

如果你的模式是静态的,你可以使用 generateschema 管理命令:

./manage.py generateschema --file openapi-schema.yml

一旦以这种方式生成模式,你可以用任何不能被模式生成器自动推断的额外信息来注释它。

你可能希望将你的API模式纳入版本控制,并在每次新发布时更新它,或者从你的网站的静态媒体提供API模式。

使用 SchemaView 生成动态模式

如果你需要动态模式,因为外键选择依赖于数据库值,例如,你可以路由一个 SchemaView ,它将按需生成和提供你的模式。

要路由一个 SchemaView ,请使用 get_schema_view() 辅助函数。

urls.py 中:

from rest_framework.schemas import get_schema_view

urlpatterns = [
    # ...
    # 使用 `get_schema_view()` 辅助函数将 `SchemaView` 添加到项目URL中。
    #   * `title` 和 `description` 参数传递给 `SchemaGenerator`。
    #   * 提供视图名称以供 `reverse()` 使用。
    path(
        "openapi",
        get_schema_view(
            title="你的项目", description="所有事物的API……", version="1.0.0"
        ),
        name="openapi-schema",
    ),
    # ...
]

get_schema_view()

get_schema_view() 辅助函数接受以下关键字参数:

  • title :可用于为模式定义提供一个描述性标题。
  • description :更长的描述性文字。
  • version :API的版本。
  • url :可用于传递模式的规范基础URL。
schema_view = get_schema_view(
      title='服务器监控API',
      url='https://www.example.org/api/'
)
  • urlconf :一个字符串,表示你想要为其生成API模式的URL配置的导入路径。默认为Django的 ROOT_URLCONF 设置。
schema_view = get_schema_view(
      title='服务器监控API',
      url='https://www.example.org/api/',
      urlconf='myproject.urls'
)
  • patterns :一个URL模式列表,用于限制模式内省的范围。如果你只想在模式中暴露 myproject.api URL:
schema_url_patterns = [
      path('api/', include('myproject.api.urls')),
]

schema_view = get_schema_view(
      title='服务器监控API',
      url='https://www.example.org/api/',
      patterns=schema_url_patterns,
)
  • public :可用于指定模式是否应该绕过视图权限。默认为False。
  • generator_class :可用于指定要传递给 SchemaViewSchemaGenerator 子类。
  • authentication_classes :可用于指定将应用于模式端点的身份验证类列表。默认为 settings.DEFAULT_AUTHENTICATION_CLASSES
  • permission_classes :可用于指定将应用于模式端点的权限类列表。默认为 settings.DEFAULT_PERMISSION_CLASSES
  • renderer_classes :可用于传递可用于渲染API根端点的渲染器类集合。

SchemaGenerator

模式级别自定义

from rest_framework.schemas.openapi import SchemaGenerator

SchemaGenerator 是一个类,它遍历一个路由的URL模式列表,请求每个视图的模式,并收集生成的OpenAPI模式。

通常你不需要自己实例化 SchemaGenerator ,但你可以这样做:

generator = SchemaGenerator(title='股票价格API')

参数:

  • title 必需 :API的名称。
  • description :更长的描述性文字。
  • version :API的版本。默认为 0.1.0
  • url :API模式的根URL。除非模式包含在路径前缀下,否则此选项不是必需的。
  • patterns :一个URL列表,用于在生成模式时进行内省。默认为项目的URL配置。
  • urlconf :一个URL配置模块名称,用于生成模式。默认为 settings.ROOT_URLCONF

为了自定义顶层模式,子类化 rest_framework.schemas.openapi.SchemaGenerator 并将你的子类作为参数提供给 generateschema 命令或 get_schema_view() 辅助函数。

get_schema(self, request=None, public=False)

返回一个表示OpenAPI模式的字典:

generator = SchemaGenerator(title='股票价格API')
schema = generator.get_schema()

request 参数是可选的,如果你希望对生成的模式应用基于用户的权限,可以使用它。

这是一个很好的覆盖点,如果你想自定义生成的字典。例如,你可能希望向顶层的 info 对象添加服务条款:

class TOSSchemaGenerator(SchemaGenerator):
    def get_schema(self, *args, **kwargs):
        schema = super().get_schema(*args, **kwargs)
        schema["info"]["termsOfService"] = "https://example.com/tos.html"
        return schema

AutoSchema

每个视图自定义

from rest_framework.schemas.openapi import AutoSchema

默认情况下,视图内省是由 AutoSchema 实例执行的,该实例通过 APIView 上的 schema 属性访问。

auto_schema = some_view.schema

AutoSchema 提供了每个视图、请求方法和路径所需的OpenAPI元素:

  • 一个OpenAPI组件列表。在DRF术语中,这些是描述请求和响应体的序列化器映射。
  • 一个适当的OpenAPI操作对象,用于描述端点,包括分页、过滤等的路径和查询参数。
components = auto_schema.get_components(...)
operation = auto_schema.get_operation(...)

在编译模式时, SchemaGenerator 为每个视图、允许的方法和路径调用 get_components()get_operation()


注意 :组件的自动内省以及许多操作参数依赖于 GenericAPIView 的相关属性和方法: get_serializer()pagination_classfilter_backends 等。对于基本的 APIView 子类,默认内省基本上仅限于URL kwarg路径参数。


AutoSchema 封装了视图内省所需的模式生成。由于这个原因,所有的模式生成逻辑都保持在一个地方,而不是分散在已经很广泛的视图、序列化器和字段API中。

保持这种模式,尽量不要让你的模式逻辑泄漏到你的视图、序列化器或字段中,当你自定义模式生成时。你可能会被诱惑做这样的事情:

class CustomSchema(AutoSchema):
    """
    使用视图上的schema_extra_info的AutoSchema子类。
    """

    ...

class CustomView(APIView):
    schema = CustomSchema()
    schema_extra_info = ...  # 一些额外信息

在这里, AutoSchema 子类去查找视图上的 schema_extra_info 。这没关系(实际上并不有害),但意味着你的模式逻辑将分散在许多不同的地方。

相反,尝试子类化 AutoSchema ,使得额外信息不会泄漏到视图中:

class BaseSchema(AutoSchema):
    """
    知道如何使用额外信息的AutoSchema子类。
    """

    ...

class CustomSchema(BaseSchema):
    extra_info = ...  # 一些额外信息

class CustomView(APIView):
    schema = CustomSchema()

这种风格稍微冗长一些,但保持了模式相关代码的封装性。在术语中,它更具有内聚性。它将使你的API代码更整洁。

如果一个选项适用于许多视图类,而不是为每个视图创建特定的子类,你可能会发现允许在你的基础 AutoSchema 子类的 __init__() 方法中指定选项更方便:

class CustomSchema(BaseSchema):
    def __init__(self, **kwargs):
        # 存储额外信息以供稍后使用
        self.extra_info = kwargs.pop("extra_info")
        super().__init__(**kwargs)

class CustomView(APIView):
    schema = CustomSchema(extra_info=...)  # 一些额外信息

这可以避免你为一个常见选项为每个视图创建自定义子类。

不是所有 AutoSchema 方法都暴露相关的 __init__() 关键字参数,但更常用的选项都暴露了。

AutoSchema 方法

get_components()

生成描述请求和响应体的OpenAPI组件,从序列化器推导其属性。

返回一个字典,将组件名称映射到生成的表示。默认情况下,它只有一对,但你可以覆盖 get_components() 以返回多对,如果你的视图使用多个序列化器。

get_component_name()

从序列化器计算组件名称。

如果你的API有重复的组件名称,你可能会看到警告。你可以覆盖 get_component_name() 或传递 component_name __init__() 关键字参数(见下文)来提供不同的名称。

get_reference()

返回对序列化器组件的引用。如果你覆盖 get_schema() ,这可能很有用。

map_serializer()

将序列化器映射到它们的OpenAPI表示。

大多数序列化器应符合标准的OpenAPI object 类型,但你可以覆盖 map_serializer() 来自定义此或其他序列化器级别的字段。

map_field()

将单个序列化器字段映射到其模式表示。基础实现将处理Django REST Framework提供的默认字段。

对于 SerializerMethodField 实例,其模式未知,或自定义字段子类,应覆盖 map_field() 以生成正确的模式:

class CustomSchema(AutoSchema):
    """扩展 ``AutoSchema`` 以添加对自定义字段模式的支持。"""

    def map_field(self, field):
        # 处理 SerializerMethodFields 或自定义字段...
        # ...
        return super().map_field(field)

第三方包的作者应提供一个 AutoSchema 子类和一个混合类,覆盖 map_field() 以便用户可以轻松地为他们的自定义字段生成模式。

get_tags()

OpenAPI按标签对操作进行分组。默认情况下,标签取自路由URL的第一个路径段。例如,一个URL如 /users/{id}/ 将生成标签 users

你可以在初始化时传递关键字参数来手动指定标签(见下文),或覆盖 get_tags() 以提供自定义逻辑。

get_operation()

返回描述端点的OpenAPI操作对象,包括分页、过滤等的路径和查询参数。

get_components() 一起,这是视图内省的主要入口点。

get_operation_id()

每个操作必须有一个唯一的操作ID。默认情况下, operationId 是从模型名称、序列化器名称或视图名称推导出来的。操作ID看起来像 “listItems”、“retrieveItem”、“updateItem” 等。 operationId 按惯例是驼峰大小写。

get_operation_id_base()

如果你有多个视图针对同一个模型,你可能会看到重复的操作ID。

为了绕过这个问题,你可以覆盖 get_operation_id_base() 以提供操作ID名称部分的不同基础。

get_serializer()

如果视图实现了 get_serializer() ,返回结果。

get_request_serializer()

默认情况下返回 get_serializer() ,但可以覆盖以区分请求和响应对象。

get_response_serializer()

默认情况下返回 get_serializer() ,但可以覆盖以区分请求和响应对象。

AutoSchema.__init__() 关键字参数

AutoSchema 提供了一些 __init__() 关键字参数,用于常见自定义,如果默认生成的值不合适。

可用的关键字参数有:

  • tags :指定一个标签列表。
  • component_name :指定组件名称。
  • operation_id_base :指定操作ID的资源名称部分。

在声明视图上的 AutoSchema 实例时传递这些关键字参数:

class PetDetailView(generics.RetrieveUpdateDestroyAPIView):
    schema = AutoSchema(
        tags=['Pets'],
        component_name='Pet',
        operation_id_base='Pet',
    )
    ...

假设有一个 Pet 模型和 PetSerializer 序列化器,这个例子中的关键字参数可能不需要。通常,只有当你有多个视图针对同一个模型,或者有多个视图具有相同名称的序列化器时,你才需要传递这些关键字参数。

如果你的视图有一些经常需要的自定义,你可以为你的项目创建一个基础 AutoSchema 子类,该子类接受额外的 __init__() 关键字参数,以避免为每个视图子类化 AutoSchema

你可能感兴趣的:(djangopython)