Равенство атрибутов перечисления Django
Я использую перечисления в модели django, например:
class AwesomeNess(Enum):
slight = "SLIGHT"
very = "VERY"
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
awesomeness = models.CharField(
max_length=255,
choices=[(tag.value, tag.name) for tag in AwesomeNess],
default=AwesomeNess.slight
)
Это работает нормально, когда я использую функцию фильтра Django, например:
d = Choice.objects.filter(awesomeness=AwesomeNess.slight)
Однако, он не работает, если я делаю:
choice_obj = Choice.objects.get(id=1)
choice_obj.awesomeness == AwesomeNess.slight # will return False
choice_obj.awesomeness == "AwesomeNess.slight" # will return True
Поскольку значения хранятся в виде строк, похоже, что Django забывает приводить их обратно к перечислению при возврате данных. Это дает несоответствия при кодировании, так как фильтры модели django могут запрашивать по перечислению, в то время как фильтрация равенства атрибутов требует, чтобы я использовал строковое представление перечисления.
EDIT: Перечисления импортированы из другого класса модели, поэтому замена его на встроенный класс выбора Django не является вариантом.
Есть ли способ обойти это? Я делаю что-то очень неправильно? Заранее благодарен! О, bwt: это на Django 2.2.24. Может быть, в более поздних версиях улучшена поддержка перечислений?
Причина, по которой это происходит, заключается в том, что выбор вызывает str
на заданном значении, и это означает, что он будет хранить "AwesomeNess.slight"
как строку (если это установлено по умолчанию).
Начиная с django-3.0, вы можете работать с TextChoices
классом [Django-doc], что совершенно аналогично использованию Enum
. Таким образом, вы можете определить TextChoices
модель с помощью:
class Choice(models.Model):
class AwesomNess(models.TextChoices):
SLIGHT = 'SLIGHT', 'slight'
VERY = 'VERY', 'very'
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
awesomeness = models.CharField(
max_length=255,
choices=AwesomeNess.choices,
default=AwesomeNess.SLIGHT
)
для старых версий необходимо указать, что вы работаете со значением из AwesomeNess
:
class AwesomeNess(Enum):
slight = 'SLIGHT'
very = 'VERY'
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
awesomeness = models.CharField(
max_length=255,
choices=[(tag.value, tag.name) for tag in AwesomeNess],
default=AwesomeNess.slight.value
)