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.42k stars 266 forks source link

read_only fields are always considered as required #1265

Open zahraaalizadeh opened 4 months ago

zahraaalizadeh commented 4 months ago

Describe the bug Read-only fields in serializers are being marked as required in the generated OpenAPI schema, even when explicitly defined with read_only=True and required=False.

To Reproduce Steps to reproduce the behavior:

from rest_framework import serializers

class OrderSerializer(serializers.Serializer):
    order_id = serializers.IntegerField()
    status = serializers.CharField(read_only=True, required=False)
    created_at = serializers.DateTimeField()

class OrderResponse(serializers.Serializer):
    order = OrderSerializer()
    message = serializers.CharField(read_only=True, required=False)
    success = serializers.BooleanField()

Using DRF Spectacular to generate the schema results in message and status being marked as required, even though they are explicitly defined with read_only=True and required=False.

openapi: 3.0.3
info:
  title: aa
  version: 1.0.0
  description: aa
paths:
  /create-order/:
    post:
      operationId: create_order_create
      tags:
      - create-order
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderResponse'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/OrderResponse'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/OrderResponse'
        required: true
      security:
      - cookieAuth: []
      - basicAuth: []
      - {}
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
          description: ''
  components:
  schemas:
    Order:
      type: object
      properties:
        order_id:
          type: integer
        status:
          type: string
          readOnly: true
        created_at:
          type: string
          format: date-time
      required:
      - created_at
      - order_id
      - status
    OrderResponse:
      type: object
      properties:
        order:
          $ref: '#/components/schemas/Order'
        message:
          type: string
          readOnly: true
        success:
          type: boolean
      required:
      - message
      - order
      - success
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
    cookieAuth:
      type: apiKey
      in: cookie
      name: sessionid

Expected behavior Read-only fields on the response should not be marked as required in the generated OpenAPI schema. The fields should be optional in the schema, reflecting their read_only=True and required=False status.

tfranzel commented 4 months ago

Hi, this is actually intended behavior as it closely resembles what DRF is actually doing. On response, those "not required" fields are basically always present. The required property of DRF refers rather to the request than the response.

Turn of the heuristic with setting the var True:

https://github.com/tfranzel/drf-spectacular/blob/cc916372a0e3fafc3af48f94dd1a985f5fc466e9/drf_spectacular/settings.py#L38

zahraaalizadeh commented 4 months ago

True! Thanks for the clue!