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

Returning an Enum from a SerializerMethod #1383

Open
johnthagen opened this issue Feb 19, 2025 · 6 comments
Open

Returning an Enum from a SerializerMethod #1383

johnthagen opened this issue Feb 19, 2025 · 6 comments

Comments

@johnthagen
Copy link
Contributor

johnthagen commented Feb 19, 2025

Is it possible to express this:

class Item(Model):
    name = TextField()

@unique
class Color(Enum):
    Red = "red"
    Green = "green"
    Blue = "blue"


class ItemSerializer(ModelSerializer):
    color = SerializerMethodField()

    def get_color(self, instance) -> Color:
        return Color.Red.value

    class Meta:
        model = Item
        fields = "__all__"

We've been able to use Enums directly within Models, using https://github.com/akx/django-enumfields2 and that translates properly into an OpenAPI enum.

Is there a way to expose similar functionality through a SerializerMethod in a way drf-spectacular can process?

@johnthagen johnthagen changed the title Returning a Enum from a SerializerMethod Returning an Enum from a SerializerMethod Feb 19, 2025
@johnthagen
Copy link
Contributor Author

johnthagen commented Feb 19, 2025

Interesting, this does seem to somewhat work, even though from looking at the code and they type hints on @extend_schema_field, I didn't see Enum so I was expecting this to not work?

_KnownPythonTypes = typing.Type[typing.Union[
    str, float, bool, bytes, int, dict, UUID, Decimal, datetime, date, time,
    timedelta, IPv4Address, IPv6Address,
]]

I guess I'd like to check that this is intended behavior 😄 .

Edit: This only partially seems to work.

@johnthagen
Copy link
Contributor Author

So this seems to generate:

    Item:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        color:
          allOf:
          - $ref: '#/components/schemas/ColorEnum'
          readOnly: true
        name:
          type: string
      required:
      - color
      - id
      - name

... 

    ColorEnum:
      enum:
      - red
      - green
      - blue

But something is not correct because the Swagger UI shows:

Image Image

And "ENUM_NAME_OVERRIDES" does not seem to work within drf-spectacular.

@johnthagen
Copy link
Contributor Author

Switching to @extend_schema_field seems to produce the same result.

    @extend_schema_field(Color)
    def get_color(self, instance) -> Any:
        return Color.Red.value

@johnthagen
Copy link
Contributor Author

johnthagen commented Feb 19, 2025

I think what's causing the error is the

allOf:

line. My other EnumFields that work properly don't have that wrapping the $ref in the generated OpenAPI spec.

@johnthagen
Copy link
Contributor Author

@tfranzel If there is a proper way to do this, I'm also happy to add a FAQ entry about it. 😃

@johnthagen
Copy link
Contributor Author

Okay, not sure why I didn't think of this at first, but using an EnumField does make this work:

from enumfields.drf import EnumField

class Item(Model):
    name = TextField()

@unique
class Color(Enum):
    Red = "red"
    Green = "green"
    Blue = "blue"


class ItemSerializer(ModelSerializer):
    color = SerializerMethodField()

    @extend_schema_field(EnumField(Color))
    def get_color(self, instance) -> str:
        return Color.Red.value

    class Meta:
        model = Item
        fields = "__all__"

If this is indeed the proper way to do this, I'm happy to make an FAQ. Also, I could potentially see someone who doesn't use https://github.com/akx/django-enumfields2 wanting to export a simple Enum from a SerializerMethodField, so perhaps it's still worth a more generic solution within drf-spectacular?

Maybe natively supporting the StrEnum as one of the _KnownPythonTypes?

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

No branches or pull requests

1 participant