【问题标题】:Reusing choice definition in swagger generation with Django Rest Framework使用 Django Rest Framework 在 swagger 生成中重用选择定义
【发布时间】:2019-06-20 13:04:36
【问题描述】:

我有一个使用 drf-yasg 生成 swagger.json 文件的 Django (Django Rest Framework) 网络服务。在模型中,我有几个枚举/选择字段用于多个地方。默认情况下,drf-yasg 为每个事件定义了内联字段:

Choices = serializers.ChoiceField(choices=['a', 'b', 'c'])

class SomeObject(serializers.Serializer):
    field_1 = Choices
    field_2 = Choices

在 swagger 文件中生成以下定义:

{
  "definitions": {
    "SomeObject": {
      "required": [ "field_1", "field_2" ],
      "type": "object",
      "properties": {
        "field_1": {
          "title": "Field 1",
          "type": "string",
          "enum": [ "a", "b", "c" ]
        },
        "field_2": {
          "title": "Field 1",
          "type": "string",
          "enum": [ "a", "b", "c" ]
        }
      }
    }
  }
}

这是一个小问题,因为它使客户端代码生成工具生成每个枚举作为自己的类型,而不是重用定义。因此,我想创建一个像这样的 swaggerfile:

{
  "definitions": {
    "Choices": {
      "title": "Field 1",
      "type": "string",
      "enum": [ "a", "b", "c" ]
    },
    "SomeObject": {
      "required": [ "field_1", "field_2" ],
      "type": "object",
      "properties": {
        "field_1": {
          "$ref": "#/definitions/Choices"
        },
        "field_2": {
          "$ref": "#/definitions/Choices"
        }
      }
    }
  }
}

是否可以在 Django Rest 框架中启用此行为?

【问题讨论】:

    标签: python python-3.x django-rest-framework drf-yasg


    【解决方案1】:

    万一有人看到这个并需要一些指示。我最终实现了如下:

    创建ChoiceField 的子类,用于指示枚举应作为引用实现,以及其他一些检查。检查str 是为了确保序列化知道如何处理这些值:

    from rest_framework import serializers
    
    from enum import Enum
    
    class ReferenceEnumField(serializers.ChoiceField):
      def __init__(self, enum_type, **kwargs):
        if not issubclass(enum_type, str):
          raise TypeError("enum_type should inherit from str in order to be json-serializable.")
        if not issubclass(enum_type, Enum):
          raise TypeError("enum_type should be an Enum")
        self.enum_name = enum_type.__name__
        super().__init__(choices=[enum.name for enum in enum_type], **kwargs)
    

    然后是可以添加到装饰器中的inspector,如下:

    from drf_yasg.inspectors.base import NotHandled
    from drf_yasg.inspectors.field import ReferencingSerializerInspector
    from drf_yasg import openapi
    from drf_yasg.errors import SwaggerGenerationError
    
    from .ReferenceEnumfield import ReferenceEnumField
    
    class EnumAsReferenceInspector(ReferencingSerializerInspector):
      accepting_objects = True
    
      @classmethod
      def set_accepting_objects(cls, value):
        cls.accepting_objects = value
    
      def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs):
        SwaggerType, ChildSwaggerType = self._get_partial_types(field, swagger_object_type, use_references, **kwargs)
    
    
        if EnumAsReferenceInspector.accepting_objects and isinstance(field, ReferenceEnumField):
          try:
            # Avoid infinite recursion by setting the class to not accept objects to serialize.
            EnumAsReferenceInspector.set_accepting_objects(False)
            if swagger_object_type != openapi.Schema:
              raise SwaggerGenerationError("cannot instantiate nested serializer as " + swagger_object_type.__name__)
    
            ref_name = field.enum_name
    
            def make_schema_definition(enum=field):
              return self.probe_field_inspectors(enum, ChildSwaggerType, use_references)
            if not ref_name or not use_references:
              return make_schema_definition()
    
            definitions = self.components.with_scope(openapi.SCHEMA_DEFINITIONS)
            actual_schema = definitions.setdefault(ref_name, make_schema_definition)
            actual_schema._remove_read_only()
    
            return openapi.SchemaRef(definitions, ref_name)
          finally:
            EnumAsReferenceInspector.set_accepting_objects(True)
    
        return NotHandled
    

    它是从库中的一些其他代码拼凑而成的,所以我不确定是否有可以省略或以不同方式完成的行,但它可以解决问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-21
      • 1970-01-01
      • 2016-01-26
      • 2012-05-26
      • 2017-01-15
      • 2017-10-16
      • 2014-06-05
      • 1970-01-01
      相关资源
      最近更新 更多