diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 29ac90ea8..a96fa6e65 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -1053,7 +1053,11 @@ class OpenAPIRenderer(BaseRenderer): assert yaml, 'Using OpenAPIRenderer, but `pyyaml` is not installed.' def render(self, data, media_type=None, renderer_context=None): - return yaml.dump(data, default_flow_style=False, sort_keys=False).encode('utf-8') + # disable yaml advanced feature 'alias' for clean, portable, and readable output + class Dumper(yaml.Dumper): + def ignore_aliases(self, data): + return True + return yaml.dump(data, default_flow_style=False, sort_keys=False, Dumper=Dumper).encode('utf-8') class JSONOpenAPIRenderer(BaseRenderer): diff --git a/tests/schemas/test_openapi.py b/tests/schemas/test_openapi.py index 0bee0a167..cfa2e89ef 100644 --- a/tests/schemas/test_openapi.py +++ b/tests/schemas/test_openapi.py @@ -8,7 +8,7 @@ from django.utils.translation import gettext_lazy as _ from rest_framework import filters, generics, pagination, routers, serializers from rest_framework.compat import uritemplate from rest_framework.parsers import JSONParser, MultiPartParser -from rest_framework.renderers import JSONRenderer +from rest_framework.renderers import JSONRenderer, OpenAPIRenderer from rest_framework.request import Request from rest_framework.schemas.openapi import AutoSchema, SchemaGenerator @@ -473,6 +473,19 @@ class TestOperationIntrospection(TestCase): assert len(success_response['content'].keys()) == 1 assert 'application/json' in success_response['content'] + def test_openapi_yaml_rendering_without_aliases(self): + renderer = OpenAPIRenderer() + + reused_object = {'test': 'test'} + data = { + 'o1': reused_object, + 'o2': reused_object, + } + assert ( + renderer.render(data) == b'o1:\n test: test\no2:\n test: test\n' or + renderer.render(data) == b'o2:\n test: test\no1:\n test: test\n' # py <= 3.5 + ) + def test_serializer_filefield(self): path = '/{id}/' method = 'POST'