6

I have a Enum class:

class Group(enum.Enum):
    user = 0
    manager = 1
    admin = 2

I have a pydantic model:

class User(BaseModel):
    id: int
    username: str
    group: Group

It generated serialised to json following:

{
    "id": 5,
    "username": "admin",
    "group": 2
}

However, I would like to get the name of the enum field instead of its value, so it should be:

{
    "id": 5,
    "username": "admin",
    "group": "admin"
}

Is this possible at all? If so, how?

Anton Daneyko
  • 6,528
  • 5
  • 31
  • 59
Martin Fischer
  • 469
  • 1
  • 7
  • 21

4 Answers4

2

You are not trying to "load" anything, your problem is that you want to encode your Pydantic field using the Enum name instead of the value, when serialising your model to JSON.

All you need to do is add a Config class to your BaseModel subclass that specifies a JSON encoder for the Group type. The json_encoders attribute is a dict keyed on type with serialiser callables:

import enum
from pydantic import BaseModel


class Group(enum.Enum):
    user = 0
    manager = 1
    admin = 2


class User(BaseModel):
    id: int
    username: str
    group: Group

    class Config:
        json_encoders = {Group: lambda g: g.name}


user = User(id=5, username="admin", group=2)
print(user)  # id=5 username='admin' group=<Group.admin: 2>
print(user.json())  # {"id": 5, "username": "admin", "group": "admin"}
bfontaine
  • 18,169
  • 13
  • 73
  • 107
NeilG
  • 3,886
  • 2
  • 22
  • 30
  • 2
    For others who may want to go further, and actually *validate* their Enum by name, that is to *create* the `BaseModel` using Enum names instead of values, try this: https://github.com/pydantic/pydantic/discussions/2980 – NeilG Feb 27 '23 at 23:54
  • There is also this question that tackles customised Enums including modifying the schema and validating input by name instead of value - *and* the Enum is loaded dynamically: https://stackoverflow.com/questions/75587442/validate-pydantic-dynamic-float-enum-by-name-with-openapi-description – NeilG Mar 03 '23 at 13:01
1

You could override the dunder method repr in the Enum class in this way:

class Group(enum.Enum):
    user = 0
    manager = 1
    admin = 2

    def __repr__(self) -> str:
        return self.name
KE-py
  • 11
  • 2
  • Answer needs supporting information Your answer could be improved with additional supporting information. Please [edit](https://stackoverflow.com/posts/76233530/edit) to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](https://stackoverflow.com/help/how-to-answer). – moken May 17 '23 at 03:02
0

In the pydantic Github I found a discussion tackling this issue: Map string value to int #598

samuelcolvin suggested this:

class Choices(int, Enum):
    anne = 1
    ben = 2
    charlie = 3
    dave = 4

    @classmethod
    def __get_validators__(cls):
        cls.lookup = {v: k.value for v, k in cls.__members__.items()}
        yield cls.validate

    @classmethod
    def validate(cls, v):
        try:
            return cls.lookup[v]
        except KeyError:
            raise ValueError('invalid value')

class Model(BaseModel):
    choice: Choices

debug(Model(choice='charlie'))
Themerius
  • 1,861
  • 1
  • 19
  • 33
-1
class Group(enum.Enum):
    user = "user"
    manager = "manager"
    admin = "admin"

did the trick :o

Martin Fischer
  • 469
  • 1
  • 7
  • 21