Как повторно использовать существующий python Enum в Django для выбора?

Django имеет свои собственные типы перечисления, такие как model.TextChoices.

Однако, если вы уже используете традиционные объекты python Enum в своей кодовой базе, было бы неплохо повторно использовать их для определения полей без переопределения всех значений.

Есть ли элегантный прямой способ сделать это без излишнего количества шаблонов?

Что я пробовал:

  • создание класса models.TextChoices из Enum кажется невозможным без ручного объявления значений
  • создание choices параметра из Enum вместо того, чтобы иметь дело с models.TextChoices, но тогда такие вещи, как obj.field == ENUM.XXX не будут работать, потому что Enums не делают сравнения значений, как models.TextChoices, среди прочего.

Есть ли элегантный способ сделать это?


form enum import Enum

class YEAR_IN_SCHOOL(Enum):
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    GRADUATE = 'GR'

class MyModel(models.Model):
    year_in_school = django_model_field_choices_using_enum(YEAR_IN_SCHOOL)

Так что:

  • Сравнение с работой ENUM
my_model.year_in_school == YEAR_IN_SCHOOL.FRESHMAN
  • Сохранение с помощью Enum работает
my_model.year_in_school = YEAR_IN_SCHOOL.FRESHMAN
my_model.save()

Вы можете определить его как обычный django models.CharField с choices из вашего Enum

I.e.:

class MyModel(models.Model):
    year_in_school = models.CharField(max_length=2, 
        choices=[(x.value, x.name) for x in YEAR_IN_SCHOOL]
    )

Однако использование в этом случае будет немного другим (необходимо указать .value при сравнении/сохранении:

).
my_model.year_in_school == YEAR_IN_SCHOOL.FRESHMAN.value

Если вы хотите иметь его без .value - то удалите Enum - т.е. сделайте простой класс.

Тогда поиск вариантов будет с inspect:

import inspect

class YEAR_IN_SCHOOL:
    FRESHMAN = 'FR'
    SOPHOMORE = 'SO'
    JUNIOR = 'JR'
    SENIOR = 'SR'
    GRADUATE = 'GR'

choices = [(y, x) for x, y in inspect.getmembers(YEAR_IN_SCHOOL)]

И задание/сравнение будет таким же, как в вашем вопросе

Вернуться на верх