From 2828132264afc4131facdc80fc4f5b5b80f862b0 Mon Sep 17 00:00:00 2001 From: Glenn Matthews Date: Fri, 3 Mar 2023 09:24:57 -0500 Subject: [PATCH] Add option to provide a callable for PolymorphicProxySerializer.serializers --- drf_spectacular/utils.py | 20 +++++++++++++++++++- tests/test_polymorphic.py | 21 ++++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/drf_spectacular/utils.py b/drf_spectacular/utils.py index 03b52b4b..c795b0f1 100644 --- a/drf_spectacular/utils.py +++ b/drf_spectacular/utils.py @@ -64,11 +64,19 @@ def create(self, request, *args, **kwargs): *drf-spectacular* processes the serializer. In those cases you can explicitly state the mapping with ``{'legal': LegalPersonSerializer, ...}``, but it is then your responsibility to have a valid mapping. + + It is also permissible to provide a callable with no parameters for ``serializers``, + such as a lambda that will return an appropriate list or dict when evaluated. """ def __init__( self, component_name: str, - serializers: Union[Sequence[_SerializerType], Dict[str, _SerializerType]], + serializers: Union[ + Sequence[_SerializerType], + Dict[str, _SerializerType], + Callable[[], Sequence[_SerializerType]], + Callable[[], Dict[str, _SerializerType]] + ], resource_type_field_name: Optional[str], many: Optional[bool] = None, ): @@ -88,6 +96,16 @@ def __new__(cls, *args, **kwargs): instance._many = many return instance + @property + def serializers(self): + if callable(self._serializers): + self._serializers = self._serializers() + return self._serializers + + @serializers.setter + def serializers(self, value): + self._serializers = value + @property def data(self): self._trap() diff --git a/tests/test_polymorphic.py b/tests/test_polymorphic.py index 22e63298..2f5665cf 100644 --- a/tests/test_polymorphic.py +++ b/tests/test_polymorphic.py @@ -93,8 +93,27 @@ def create(self, request, *args, **kwargs): def partial_update(self, request, *args, **kwargs): return Response({}) # pragma: no cover + lambda_poly_proxy = PolymorphicProxySerializer( + component_name='MetaPerson', + serializers=lambda: [LegalPersonSerializer, NaturalPersonSerializer], + resource_type_field_name='type', + ) + + class LambdaPersonViewSet(viewsets.GenericViewSet): + @extend_schema(request=lambda_poly_proxy, responses=lambda_poly_proxy) + def create(self, request, *args, **kwargs): + return Response({}) # pragma: no cover + + @extend_schema( + request=lambda_poly_proxy, + responses=lambda_poly_proxy, + parameters=[OpenApiParameter('id', int, OpenApiParameter.PATH)], + ) + def partial_update(self, request, *args, **kwargs): + return Response({}) # pragma: no cover + -@pytest.mark.parametrize('viewset', [ImplicitPersonViewSet, ExplicitPersonViewSet]) +@pytest.mark.parametrize('viewset', [ImplicitPersonViewSet, ExplicitPersonViewSet, LambdaPersonViewSet]) def test_polymorphic(no_warnings, viewset): assert_schema( generate_schema('persons', viewset),