架构
可供机器读取的 [架构] 描述了可通过 API 获得的资源、它们的 URL、它们的表示方式以及它们支持的操作。
— Heroku,Heroku 平台 API 的 JSON 架构
弃用通知
REST 框架内置的 OpenAPI 架构生成支持已弃用,取而代之的是可以提供此功能的第三方软件包。内置支持将移至一个单独的软件包,然后在后续版本中逐步淘汰。
作为全面替代,我们推荐使用 drf-spectacular 软件包。它广泛支持从 REST 框架 API 生成 OpenAPI 3 架构,并提供了自动和可自定义选项。有关详细信息,请参阅 记录您的 API。
API 架构是一个有用的工具,允许一系列用例,包括生成参考文档或驱动可以与您的 API 交互的动态客户端库。
Django REST 框架提供对 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 = [
# ...
# Use the `get_schema_view()` helper to add a `SchemaView` to project URLs.
# * `title` and `description` parameters are passed to `SchemaGenerator`.
# * Provide view name for use with `reverse()`.
path(
"openapi",
get_schema_view(
title="Your Project", description="API for all things …", 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='Server Monitoring API', url='https://www.example.org/api/' ) -
urlconf:表示要为其生成 API 架构的 URL conf 的导入路径的字符串。这默认为 Django 的ROOT_URLCONF设置的值。schema_view = get_schema_view( title='Server Monitoring API', url='https://www.example.org/api/', urlconf='myproject.urls' ) -
patterns:用于将架构自省限制为的 URL 模式列表。如果你只想在架构中公开myproject.apiURLschema_url_patterns = [ path('api/', include('myproject.api.urls')), ] schema_view = get_schema_view( title='Server Monitoring API', url='https://www.example.org/api/', patterns=schema_url_patterns, )public:可用于指定架构是否应绕过视图权限。默认为 False
-
generator_class:可用于指定要传递给SchemaView的SchemaGenerator子类。 authentication_classes:可用于指定将应用于架构端点的身份验证类列表。默认为settings.DEFAULT_AUTHENTICATION_CLASSESpermission_classes:可用于指定将应用于架构端点的权限类列表。默认为settings.DEFAULT_PERMISSION_CLASSES。renderer_classes:可用于传递可用于呈现 API 根端点的渲染器类集。
SchemaGenerator
架构级自定义
from rest_framework.schemas.openapi import SchemaGenerator
SchemaGenerator 是一个类,它遍历路由的 URL 模式列表,请求每个视图的架构,并整理结果 OpenAPI 架构。
通常你不需要自己实例化 SchemaGenerator,但你可以像这样
generator = SchemaGenerator(title='Stock Prices 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='Stock Prices 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_class、filter_backends 等。对于基本的 APIView 子类,由于这个原因,默认内省基本上仅限于 URL 关键字参数路径参数。
AutoSchema 封装了架构生成所需的视图内省。因此,所有架构生成逻辑都保存在一个地方,而不是分散在已经广泛的视图、序列化程序和字段 API 中。
遵循此模式,在自定义架构生成时,尽量不要让架构逻辑泄漏到自己的视图、序列化程序或字段中。你可能会倾向于做类似这样的事情
class CustomSchema(AutoSchema):
"""
AutoSchema subclass using schema_extra_info on the view.
"""
...
class CustomView(APIView):
schema = CustomSchema()
schema_extra_info = ... # some extra info
在这里,AutoSchema 子类在视图中查找 schema_extra_info。这是可以的(实际上并没有什么害处),但这意味着你的架构逻辑最终会分散在许多不同的地方。
相反,尝试对 AutoSchema 进行子类化,以便 extra_info 不会泄漏到视图中
class BaseSchema(AutoSchema):
"""
AutoSchema subclass that knows how to use extra_info.
"""
...
class CustomSchema(BaseSchema):
extra_info = ... # some extra info
class CustomView(APIView):
schema = CustomSchema()
这种风格稍微冗长一些,但保持了与架构相关的代码的封装。在术语中,它更内聚。它将使你的其他 API 代码更加简洁。
如果某个选项适用于多个视图类,而不是为每个视图创建特定的子类,你可能会发现允许将该选项指定为基本 AutoSchema 子类的 __init__() 关键字参数更方便
class CustomSchema(BaseSchema):
def __init__(self, **kwargs):
# store extra_info for later
self.extra_info = kwargs.pop("extra_info")
super().__init__(**kwargs)
class CustomView(APIView):
schema = CustomSchema(extra_info=...) # some extra info
这样可以节省你为常用选项为每个视图创建自定义子类的麻烦。
并非所有 AutoSchema 方法都公开相关的 __init__() kwargs,但对于更常用的选项来说,它们确实公开。
AutoSchema 方法
get_components()
生成描述请求和响应正文的 OpenAPI 组件,从序列化器派生其属性。
返回将组件名称映射到生成表示形式的字典。默认情况下,它只包含一对,但你可以覆盖 get_components() 以返回多对,如果你的视图使用多个序列化器。
get_component_name()
从序列化器计算组件的名称。
如果你的 API 具有重复的组件名称,你可能会看到警告。如果是这样,你可以覆盖 get_component_name() 或传递 component_name __init__() kwarg(见下文)以提供不同的名称。
get_reference()
返回对序列化器组件的引用。如果你覆盖 get_schema(),这可能很有用。
map_serializer()
将序列化器映射到其 OpenAPI 表示形式。
大多数序列化器都应该符合标准的 OpenAPI object 类型,但你可能希望覆盖 map_serializer() 以自定义此字段或其他序列化器级别的字段。
map_field()
将各个序列化器字段映射到其架构表示形式。基本实现将处理 Django REST Framework 提供的默认字段。
对于 SerializerMethodField 实例,其架构未知,或者自定义字段子类,你应该覆盖 map_field() 以生成正确的架构
class CustomSchema(AutoSchema):
"""Extension of ``AutoSchema`` to add support for custom field schemas."""
def map_field(self, field):
# Handle SerializerMethodFields or custom fields here...
# ...
return super().map_field(field)
第三方包的作者应该旨在提供一个 AutoSchema 子类,以及一个 mixin,覆盖 map_field(),以便用户可以轻松地为其自定义字段生成架构。
get_tags()
OpenAPI 按标签对操作进行分组。默认情况下,标签取自路由 URL 的第一路径段。例如,像 /users/{id}/ 这样的 URL 将生成标签 users。
你可以传递一个 __init__() kwarg 来手动指定标签(见下文),或覆盖 get_tags() 以提供自定义逻辑。
get_operation()
返回描述端点的 OpenAPI 操作对象,包括分页、过滤等路径和查询参数。
与 get_components() 一起,这是视图自省的主要入口点。
get_operation_id()
每个操作都必须有一个唯一的 operationid。默认情况下,operationId 从模型名称、序列化器名称或视图名称中推断出来。operationId 看起来像 "listItems"、"retrieveItem"、"updateItem" 等。按照惯例,operationId 是驼峰式大小写。
get_operation_id_base()
如果您有多个具有相同模型名称的视图,您可能会看到重复的 operationIds。
为了解决这个问题,您可以覆盖 `get_operation_id_base()` 来为 ID 的名称部分提供不同的基础。
get_serializer()
如果视图已实现 `get_serializer()`,则返回结果。
get_request_serializer()
默认情况下返回 `get_serializer()`,但可以覆盖它以区分请求和响应对象。
get_response_serializer()
默认情况下返回 `get_serializer()`,但可以覆盖它以区分请求和响应对象。
AutoSchema.__init__() kwargs
如果默认生成的数值不合适,AutoSchema 提供许多 `__init__()` kwargs,可用于常见自定义。
可用的 kwargs 是
tags:指定标签列表。component_name:指定组件名称。operation_id_base:指定操作 ID 的资源名称部分。
在视图中声明 `AutoSchema` 实例时,传递 kwargs
class PetDetailView(generics.RetrieveUpdateDestroyAPIView):
schema = AutoSchema(
tags=['Pets'],
component_name='Pet',
operation_id_base='Pet',
)
...
假设一个 `Pet` 模型和 `PetSerializer` 序列化器,此示例中的 kwargs 可能不需要。但是,通常情况下,如果您有多个视图针对同一模型,或有多个视图具有相同名称的序列化器,则需要传递 kwargs。
如果您的视图具有经常需要的相关自定义,您可以为您的项目创建一个基础 `AutoSchema` 子类,它采用额外的 `__init__()` kwargs 来保存每个视图的 `AutoSchema` 子类。