tfranzel / drf-spectacular

Sane and flexible OpenAPI 3 schema generation for Django REST framework.
https://drf-spectacular.readthedocs.io
BSD 3-Clause "New" or "Revised" License
2.32k stars 259 forks source link

The read_only field cannot be used properly in swaggerUI #759

Open xingxingzaixian opened 2 years ago

xingxingzaixian commented 2 years ago

The read_only field is not displayed in the swaggerUI form-data request body, but the request cannot be sent successfully. If the READ_only field is not filled in the JSON request body, the request can be sent normally。

For example: Model Class

class TblRole(models.Model):
    name = models.CharField(max_length=64)
    desc = models.CharField(max_length=256)

    class Meta:
        db_table = 'tbl_role'

serializer Class

class RoleSerializers(serializers.ModelSerializer):
    class Meta:
        model = TblRole
        fields = '__all__'

Although the only required fields displayed in form-data are Name and desc, clicking Execute will not send the request properly

When I modify the serialized class as follows

class RoleSerializers(serializers.ModelSerializer):
    class Meta:
        model = TblRole
        exclude = ('id', )

The page displayed on SwaggerUI does not change, but the request can be sent normally

tfranzel commented 2 years ago

Hi,

generating a schema for

def test_i759(no_warnings):
    class TblRole(models.Model):
        name = models.CharField(max_length=64)
        desc = models.CharField(max_length=256)

    class RoleSerializers(serializers.ModelSerializer):
        class Meta:
            model = TblRole
            fields = '__all__'

    class XViewset(viewsets.ModelViewSet):
        serializer_class = RoleSerializers
        queryset = TblRole.objects.none()

    schema = generate_schema('/x', XViewset)

    assert_schema(schema, 'tests/test_i759.yml')

generates the following schema. In SwaggerUI id is readOnly because its the primary key and not sending it will not break the ModelSerializer parsing like that. That is covered dozens of times in the tests. Also form-data look ok to me. To me this all looks like it should be. Not sure why your server rejects it and I would guess there is some other issue.

  1. SwaggerUI does not show the id for me on example request or "try it out".
  2. and I'm quite certain the API would simply ignore the field if its readOnly and not fail.
openapi: 3.0.3
info:
  title: ''
  version: 0.0.0
paths:
  /x/:
    get:
      operationId: x_list
      tags:
      - x
      security:
      - cookieAuth: []
      - basicAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/RoleSerializers'
          description: ''
    post:
      operationId: x_create
      tags:
      - x
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleSerializers'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/RoleSerializers'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/RoleSerializers'
        required: true
      security:
      - cookieAuth: []
      - basicAuth: []
      - {}
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleSerializers'
          description: ''
  /x/{id}/:
    get:
      operationId: x_retrieve
      parameters:
      - in: path
        name: id
        schema:
          type: integer
        description: A unique integer value identifying this tbl role.
        required: true
      tags:
      - x
      security:
      - cookieAuth: []
      - basicAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleSerializers'
          description: ''
    put:
      operationId: x_update
      parameters:
      - in: path
        name: id
        schema:
          type: integer
        description: A unique integer value identifying this tbl role.
        required: true
      tags:
      - x
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleSerializers'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/RoleSerializers'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/RoleSerializers'
        required: true
      security:
      - cookieAuth: []
      - basicAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleSerializers'
          description: ''
    patch:
      operationId: x_partial_update
      parameters:
      - in: path
        name: id
        schema:
          type: integer
        description: A unique integer value identifying this tbl role.
        required: true
      tags:
      - x
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchedRoleSerializers'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/PatchedRoleSerializers'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/PatchedRoleSerializers'
      security:
      - cookieAuth: []
      - basicAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleSerializers'
          description: ''
    delete:
      operationId: x_destroy
      parameters:
      - in: path
        name: id
        schema:
          type: integer
        description: A unique integer value identifying this tbl role.
        required: true
      tags:
      - x
      security:
      - cookieAuth: []
      - basicAuth: []
      - {}
      responses:
        '204':
          description: No response body
components:
  schemas:
    PatchedRoleSerializers:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        name:
          type: string
          maxLength: 64
        desc:
          type: string
          maxLength: 256
    RoleSerializers:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        name:
          type: string
          maxLength: 64
        desc:
          type: string
          maxLength: 256
      required:
      - desc
      - id
      - name
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
    cookieAuth:
      type: apiKey
      in: cookie
      name: sessionid
SvenMeiLing commented 5 months ago

swaggerUI form-data请求体中不显示read_only字段,导致请求无法发送成功。如果JSON请求体中没有填写READ_only字段,则可以正常发送请求。

例如: 模型类

class TblRole(models.Model):
    name = models.CharField(max_length=64)
    desc = models.CharField(max_length=256)

    class Meta:
        db_table = 'tbl_role'

序列化器类

class RoleSerializers(serializers.ModelSerializer):
    class Meta:
        model = TblRole
        fields = '__all__'

虽然表单数据中显示的唯一必填字段是“名称”和“描述”,但单击“执行”将无法正确发送请求

当我如下修改序列化类时

class RoleSerializers(serializers.ModelSerializer):
    class Meta:
        model = TblRole
        exclude = ('id', )

SwaggerUI显示的页面没有变化,但可以正常发送请求

Perhaps the answer you need is here -> https://stackoverflow.com/questions/71495090/drf-spectacular-post-method-not-working-with-form-field , content:Add this option your SPECTACULAR_SETTINGS:

'COMPONENT_SPLIT_REQUEST': True,