Derive a Django 3.0 Choices class from existing Enum?

Viewed 260

Django 3 brought a new way to define field choides: Field.choices. This brings some adavantages, e.g. enforces uniqueness and allows supplying human readable tags.

Unfortunately, I can't find a clean way to define the choices in a non-django module, so that these choices can be imported from non-django applications. Concretely:

  • in my django app, I might have a shape that has colors.
  • these color choices are to be used in my django model, but also in other non-django packages that need to know all valid choices (e.g. analysis)

Therefore I want to define these colors as stand-alone class in exactly one place, e.g.:

class ShapeColor(Enum):
    BLUE = 1
    GREEN = 2
    RED = 3

In the past I imported this Enum 'ShapeColor' anywhere I needed it. But I have not found a clean way to translate this Enum into the new models.IntegerChoices class. I tried to inherit from my Enum:

class ColorChoices(models.IntegerChoices, ShapeColors):
    pass

But of course this gives a TypeError("Cannot extend enumerations").

It would be great if anyone had a suggestion on how to cleanly derive a django choice enum from an existing Enum or similar construct.

1 Answers

Digging into the Django code a bit, it turns out that Choices, IntegerChoices, and TextChoices are all Django's versions of the basic Enum data type. So, assuming feasibility, the easiest thing to do would be to create ShapeColor as a models.IntegerChoices directly. If that's not feasible (maybe Django is not available where your other tools are running), then the next best thing would be to create ColorChoices from ShapeColor:

ColorChoices = model.IntegerChoices(
        'ColorChoices',
        [(m.name, m.value) for m in ShapeColor],
        )
Related