diff --git a/docs/custom_spec.rst b/docs/custom_spec.rst index 418ce9c8..1f8fef0a 100644 --- a/docs/custom_spec.rst +++ b/docs/custom_spec.rst @@ -159,44 +159,52 @@ Where you can use the :func:`@swagger_auto_schema <.swagger_auto_schema>` decora Support for SerializerMethodField ********************************* -Schema generation of ``serializers.SerializerMethodField`` supported in two ways: +Schema generation of ``serializers.SerializerMethodField`` is supported in two ways: -1) The decorator ``swagger_serializer_method(serializer)`` for the use case where the serializer method - is using a serializer. e.g.: +1) The :func:`swagger_serializer_method <.swagger_serializer_method>` decorator for the use case where the serializer + method is using a serializer. e.g.: + .. code-block:: python -.. code-block:: python + from drf_yasg.utils import swagger_serializer_method - from drf_yasg.utils import swagger_serializer_method + class OtherStuffSerializer(serializers.Serializer): + foo = serializers.CharField() + class ParentSerializer(serializers.Serializer): + other_stuff = serializers.SerializerMethodField() - class OtherStuffSerializer(serializers.Serializer): - foo = serializers.CharField() + @swagger_serializer_method(serializer_or_field=OtherStuffSerializer) + def get_other_stuff(self, obj): + return OtherStuffSerializer().data - class ParentSerializer(serializers.Serializer): + Note that the ``serializer_or_field`` parameter can accept either a subclass or an instance of ``serializers.Field``. - other_stuff = serializers.SerializerMethodField() - @swagger_serializer_method(serializer=OtherStuffSerializer) - def get_other_stuff(self, obj): - return OtherStuffSerializer().data +2) For simple cases where the method is returning one of the supported types, `Python 3 type hinting`_ of the + serializer method return value can be used. e.g.: + .. code-block:: python -Note that the serializer parameter can be either be a serializer class or instance + class SomeSerializer(serializers.Serializer): + some_number = serializers.SerializerMethodField() + def get_some_number(self, obj) -> float: + return 1.0 -2) For simple cases where the method is returning one of the supported types, - `Python 3 type hinting`_ of the serializer method return value can be used. e.g.: + When return type hinting is not supported, the equivalent ``serializers.Field`` subclass can be used with + :func:`swagger_serializer_method <.swagger_serializer_method>`: - .. code-block:: python + .. code-block:: python - class SomeSerializer(serializers.Serializer): + class SomeSerializer(serializers.Serializer): + some_number = serializers.SerializerMethodField() - some_number = serializers.SerializerMethodField() + @swagger_serializer_method(serializer_or_field=serializers.FloatField) + def get_some_number(self, obj): + return 1.0 - def get_some_number(self, obj) -> float: - return 1.0 ******************************** Serializer ``Meta`` nested class diff --git a/src/drf_yasg/inspectors/field.py b/src/drf_yasg/inspectors/field.py index 51b4d267..5bd169c9 100644 --- a/src/drf_yasg/inspectors/field.py +++ b/src/drf_yasg/inspectors/field.py @@ -459,8 +459,8 @@ def get_basic_type_info_from_hint(hint_class): class SerializerMethodFieldInspector(FieldInspector): - """Provides conversion for SerializerMethodField, optionally using information from the swagger_method_field - decorator + """Provides conversion for SerializerMethodField, optionally using information from the swagger_serializer_method + decorator. """ def field_to_swagger_object(self, field, swagger_object_type, use_references, **kwargs): diff --git a/src/drf_yasg/utils.py b/src/drf_yasg/utils.py index 7de77dfe..7a544400 100644 --- a/src/drf_yasg/utils.py +++ b/src/drf_yasg/utils.py @@ -178,18 +178,18 @@ def decorator(view_method): return decorator -def swagger_serializer_method(serializer): +def swagger_serializer_method(serializer_or_field): """ Decorates the method of a serializers.SerializerMethodField to hint as to how Swagger should be generated for this field. - :param serializer: serializer class or instance + :param serializer_or_field: ``Serializer``/``Field`` class or instance :return: """ def decorator(serializer_method): # stash the serializer for SerializerMethodFieldInspector to find - serializer_method._swagger_serializer = serializer + serializer_method._swagger_serializer = serializer_or_field return serializer_method return decorator diff --git a/testproj/users/method_serializers_without_typing.py b/testproj/users/method_serializers_without_typing.py index 81edd861..85df8f6e 100644 --- a/testproj/users/method_serializers_without_typing.py +++ b/testproj/users/method_serializers_without_typing.py @@ -22,21 +22,21 @@ class MethodFieldExampleSerializer(serializers.Serializer): hinted_bool = serializers.SerializerMethodField( help_text="the type hint on the method should determine this to be a bool") - @swagger_serializer_method(serializer=serializers.BooleanField) + @swagger_serializer_method(serializer_or_field=serializers.BooleanField) def get_hinted_bool(self, obj): return True hinted_int = serializers.SerializerMethodField( help_text="the type hint on the method should determine this to be an integer") - @swagger_serializer_method(serializer=serializers.IntegerField) + @swagger_serializer_method(serializer_or_field=serializers.IntegerField) def get_hinted_int(self, obj): return 1 hinted_float = serializers.SerializerMethodField( help_text="the type hint on the method should determine this to be a number") - @swagger_serializer_method(serializer=serializers.FloatField) + @swagger_serializer_method(serializer_or_field=serializers.FloatField) def get_hinted_float(self, obj): return 1.0 @@ -44,28 +44,28 @@ def get_hinted_float(self, obj): help_text="the type hint on the method should determine this to be a decimal") # note that in this case an instance is required since DecimalField has required arguments - @swagger_serializer_method(serializer=serializers.DecimalField(max_digits=6, decimal_places=4)) + @swagger_serializer_method(serializer_or_field=serializers.DecimalField(max_digits=6, decimal_places=4)) def get_hinted_decimal(self, obj): return decimal.Decimal(1) hinted_datetime = serializers.SerializerMethodField( help_text="the type hint on the method should determine this to be a datetime") - @swagger_serializer_method(serializer=serializers.DateTimeField) + @swagger_serializer_method(serializer_or_field=serializers.DateTimeField) def get_hinted_datetime(self, obj): return datetime.datetime.now() hinted_date = serializers.SerializerMethodField( help_text="the type hint on the method should determine this to be a date") - @swagger_serializer_method(serializer=serializers.DateField) + @swagger_serializer_method(serializer_or_field=serializers.DateField) def get_hinted_date(self, obj): return datetime.date.today() hinted_uuid = serializers.SerializerMethodField( help_text="the type hint on the method should determine this to be a uuid") - @swagger_serializer_method(serializer=serializers.UUIDField) + @swagger_serializer_method(serializer_or_field=serializers.UUIDField) def get_hinted_uuid(self, obj): return uuid.uuid4() diff --git a/testproj/users/serializers.py b/testproj/users/serializers.py index c51ec390..8c5dc549 100644 --- a/testproj/users/serializers.py +++ b/testproj/users/serializers.py @@ -26,7 +26,7 @@ class UserSerializerrr(serializers.ModelSerializer): hint_example = MethodFieldExampleSerializer() - @swagger_serializer_method(serializer=OtherStuffSerializer) + @swagger_serializer_method(serializer_or_field=OtherStuffSerializer) def get_other_stuff(self, obj): """ method_field that uses a serializer internally. @@ -41,7 +41,7 @@ def get_other_stuff(self, obj): help_text="help text on field is set, so this should appear in swagger" ) - @swagger_serializer_method(serializer=serializers.IntegerField( + @swagger_serializer_method(serializer_or_field=serializers.IntegerField( help_text="decorated instance help_text shouldn't appear in swagger because field has priority")) def get_help_text_example_1(self): """ @@ -52,7 +52,7 @@ def get_help_text_example_1(self): help_text_example_2 = serializers.SerializerMethodField() - @swagger_serializer_method(serializer=serializers.IntegerField( + @swagger_serializer_method(serializer_or_field=serializers.IntegerField( help_text="instance help_text is set, so should appear in swagger")) def get_help_text_example_2(self): """ @@ -63,7 +63,7 @@ def get_help_text_example_2(self): help_text_example_3 = serializers.SerializerMethodField() - @swagger_serializer_method(serializer=serializers.IntegerField()) + @swagger_serializer_method(serializer_or_field=serializers.IntegerField()) def get_help_text_example_3(self): """ docstring is set so should appear in swagger as fallback