模式
机器可读的[模式]描述了通过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
:可用于指定要传递给SchemaView
的SchemaGenerator
子类。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_class
、 filter_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
。