oxan / djangorestframework-dataclasses

Dataclasses serializer for Django REST framework
BSD 3-Clause "New" or "Revised" License
429 stars 28 forks source link

Populate help_text on serializer #88

Open ciferkey opened 1 year ago

ciferkey commented 1 year ago

With normal DRF serializers you can specify the help_text arg on a field. Then when using drf-spectacular the text is used to populate field descriptions on the OpenAPI spec.

Is it currently possible to provide field descriptions on data classes using this library have it flow up to drf-spectacular?

oxan commented 12 months ago

No, this currently isn't supported, though I'm not opposed to adding it.

Goutte commented 7 months ago

Docstrings on dataclasses' fields are tricky to read, I'm told.

I managed to get away with adding a 'description' to field()'s metadata and some plumbing in create_field().


@dataclass
class PublisherDto:
    """
    A Publisher
    """

    slug: str = field(metadata={
        "description": "Some slug",
        # "serializer_kwargs": {  # this works, but it's verbose
        #   "help_text": "Some slug",
        # },
    })

class DtoSerializer(DataclassSerializer):

    def create_field(self, field_name: str, extra_kwargs: KWArgs) -> SerializerField:

        # Get the source field (this can be useful to represent a single dataclass field in multiple ways in the
        # serialization state).
        source = extra_kwargs.get('source', '*')
        if source == '*':
            source = field_name

        # Determine the serializer field class and keyword arguments.
        if source in self.dataclass_definition.fields:
            field = self.dataclass_definition.fields[source]

            # HERE ############################
            if 'description' in field.metadata:
                extra_kwargs = {'help_text': field.metadata['description'], **extra_kwargs}

            ###################################

            if 'serializer_kwargs' in field.metadata:  # merge extra kwargs defined in the field metadata
                extra_kwargs = {**field.metadata['serializer_kwargs'], **extra_kwargs}

            type_info = field_utils.get_type_info(self.dataclass_definition.field_types[source])
            field_class, field_kwargs = self.build_typed_field(source, type_info, extra_kwargs)
        elif hasattr(self.dataclass_definition.dataclass_type, source):
            field_class, field_kwargs = self.build_property_field(source)
        else:
            field_class, field_kwargs = self.build_unknown_field(source)

        # Include any extra kwargs defined through `Meta.extra_kwargs`
        field_kwargs = self.include_extra_kwargs(field_kwargs, extra_kwargs)

        # Create the serializer field instance.
        return field_class(**field_kwargs)
Goutte commented 7 months ago

You can also override the init to pipe the docstring of the dataclass itself :

class DtoSerializer(DataclassSerializer):
    def __init__(self, *args: Any, **kwargs: Any):
        """
        Grab the class docstring from the dataclass and set it in the serializer,
        so that the schema generator finds its and uses it.
        """
        super(DtoSerializer, self).__init__(*args, **kwargs)
        if self.dataclass_definition is not None:
            type(self).__doc__ = self.dataclass_definition.dataclass_type.__doc__
micahjsmith commented 5 months ago

This library is super cool but it was not able to meet my needs with ergonomic support for help_text. Easier for me to just manually write out the serializers instead using serializers.Serializer (than use any of the above workarounds for example). The use case is to ensure that the OpenAPI schema generated with drf-spectacular have field descriptions. Thanks all