如何隐藏自动生成的架构中的字段,或明确定义架构?

问题描述

我正在使用 drf-yasgDjango REST Framework - Yet Another Swagger Generator)为我的 RESTful API 生成文档,但它并没有完全按照我的意愿行事。我认为将 read_onlywrite_only 属性设置为 True 会隐藏文档中的字段,因为它们从请求和响应正文中被省略,但事实并非如此。我没有看到任何在装饰器中定义模式的例子,甚至只是隐藏一个字段,但如果我能学会如何做其中一件事情,我就会处于良好状态。

让我们来看一个基本的例子:用户登录

# serializers.py
class TokensSerializer(serializers.Serializer):
    """
    Serializes access and refresh tokens for responses to a logged-in user.
    """
    username = serializers.CharField(max_length=64,write_only=True)
    access = serializers.CharField(max_length=4096,read_only=True)
    refresh = serializers.CharField(max_length=4096,read_only=True)
    
    # ...


class LoginSerializer(serializers.ModelSerializer):
    """
    Serializes username,email,password,and tokens to allow for logging in.
    """
    class Meta():
        model = User
        fields = ['username','email','password','tokens']

    username = serializers.CharField(max_length=64)
    email = serializers.CharField(max_length=254,read_only=True)
    password = serializers.CharField(
        min_length=8,max_length=64,write_only=True)
    tokens = TokensSerializer(read_only=True)

    # ...

这些序列化程序分别生成 TokensLogin 模型,它们以以下 .json.yaml 格式定义:

{
  "deFinitions": {
    "Tokens": {
      "required": ["username"],"type": "object","properties": {
        "username": {
          "title": "Username","type": "string","maxLength": 64,"minLength": 1
        },"access": {
          "title": "Access","readOnly": true,"maxLength": 4096,"refresh": {
          "title": "Refresh","minLength": 1
        }
      }
    },"Login": {
      "required": ["username","password"],"email": {
          "title": "Email","maxLength": 254,"password": {
          "title": "Password","minLength": 8
        },"tokens": {
          "$ref": "#/deFinitions/Tokens"
        }
      }
    }
  }
}
deFinitions:
  Tokens:
    required:
      - username
    type: object
    properties:
      username:
        title: Username
        type: string
        maxLength: 64
        minLength: 1
      access:
        title: Access
        type: string
        readOnly: true
        maxLength: 4096
        minLength: 1
      refresh:
        title: Refresh
        type: string
        readOnly: true
        maxLength: 4096
        minLength: 1
  Login:
    required:
      - username
      - password
    type: object
    properties:
      username:
        title: Username
        type: string
        maxLength: 64
        minLength: 1
      email:
        title: Email
        type: string
        readOnly: true
        maxLength: 254
        minLength: 1
      password:
        title: Password
        type: string
        maxLength: 64
        minLength: 8
      tokens:
        $ref: '#/deFinitions/Tokens'

然而,这些并不适合每个请求或响应主体,我想要么明确定义架构,要么使用省略字段的现有架构。我不知道如何实现后者,但这是我对前者的尝试,这会导致错误

class LoginView(GenericAPIView):
    """
    View for taking in an existing user's credentials and authorizing them if valid or denying access if invalid.
    """
    serializer_class = LoginSerializer

    @swagger_auto_schema(
        responses={
            201: {
                'schema': {
                    'description': 'Todo','required': ['username','tokens'],'type': 'object','properties': {
                        'username': {
                            'title': 'Username','type': 'string','maxLength': 64,'minLength': 1
                        },'email': {
                            'title': 'Email','readOnly': True,'maxLength': 254,'tokens': {
                            '$ref': '#/deFinitions/Tokens'
                        }
                    }
                }
            }
        })
    def post(self,request):
      # ...
Failed to load API deFinition.

Errors
 
Fetch error
Internal Server Error http://localhost:8000/api/v0-alpha/?format=openapi

我能想到的唯一其他选择是为每个模式创建一个序列化程序,但这似乎比必要的更费力。有什么想法吗?

解决方法

您可以将嵌套序列化器的 Meta 类的 ref_name 设置为 None,如下所述: https://github.com/axnsan12/drf-yasg/issues/239#issuecomment-442629230