Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to set a field type on SerializerMethodField for OpenAPI schema generation? #7140

Closed
Lucidiot opened this issue Jan 13, 2020 · 4 comments

Comments

@Lucidiot
Copy link
Contributor

Consider this useless serializer:

class MySerializer(serializers.Serializer):

    random_number = serializers.SerializerMethodField()

    def get_random_number(self):
        # Chosen by fair dice roll.
        # Guaranteed to be random.
        return 4

Assuming you added this serializer in an endpoint and generated the OpenAPI schema, the serializer would look like this:

properties:
  random_number:
    type: string
  required:
  - random_number

The issue here is there is no way to tell DRF to use type: number here. I thought of a few possibilities:

  • An output_field attribute, like serializers.SerializerMethodField(output_field=serializers.IntegerField()), similarly to Django's Query Expressions

  • A decorator, like openapi_type(serializers.SerializerMethodField(), serializers.IntegerField())

  • An attribute, similarly to setting descriptions on admin actions:

    random_number = serializers.SerializerMethodField()
    
    def get_random_number(self):
        return 4
    
    get_random_number.output_field = serializers.IntegerField()
  • Simply something DRF does not support, which probably should be documented somewhere as a possible caveat.

@carltongibson
Copy link
Collaborator

Hi @Lucidiot.

I guess the immediate way to do this would be to override AutoSchema._map_field().

You can either do that per-serializer/view to expect the field in question, or add an attribute like you say.

We'll come round to something in this way eventually, but currently I'm not sure about the best option, in terms of API.

@knyghty
Copy link

knyghty commented Mar 16, 2020

For me, I think the API I'd prefer is something using type hinting like:

def get_foo(self, obj) -> int:
    return 1

It works in every Python version currently supported. This idea was used in #7089 but it wasn't separated out into another PR. Looking at that implementation, it seems like it doesn't handle collections. At some point you'd be better using a nested serializer, but I think simple cases like List[int], List[str], Dict[str, int] etc. should be supported.

@carlfarrington what do you think? Is it worth trying this approach or are there problems with it? If it's worth trying, is it also worth getting something basic in that can handle basic types and ignore nested fields for now or would we want (nested or not) arrays and objects from the start?

@carltongibson
Copy link
Collaborator

We'll promote and document map_field() for 3.12. That's the right way to go here.

@carltongibson carltongibson self-assigned this Apr 6, 2020
carltongibson added a commit to carltongibson/django-rest-framework that referenced this issue Apr 6, 2020
carltongibson added a commit to carltongibson/django-rest-framework that referenced this issue Apr 10, 2020
@collinscangarella
Copy link

https://www.django-rest-framework.org/api-guide/schemas/#map_field

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants