Как сопоставить текст Django TextChoices с выбором?
Предположим, у меня есть такой код, вдохновленный документацией Django о типах перечислений:
class YearInSchool(models.TextChoices):
FRESHMAN = 'FR', 'Freshman'
SOPHOMORE = 'SO', 'Sophomore'
JUNIOR = 'JR', 'Junior'
SENIOR = 'SR', 'Senior'
GRADUATE = 'GR', 'Graduate'
Теперь предположим, что у меня есть строка "Sophomore". Как мне перейти от нее к YearInSchool.SOPHOMORE
?
Единственное, что я могу придумать, это цикл:
the_str = "Sophomore"
val = None
for val1, label in YearInSchool.choices:
if label == the_str:
val = YearInSchool(val1)
break
assert YearInSchool.SOPHOMORE == val
Это кажется неудобным. Есть ли лучший способ?
Вы можете использовать getattr
:
the_str = 'Sophomore'
try:
val = getattr(YearInSchool, the_str.upper())
except AttributeError:
raise AttributeError(f'{the_str.upper()} not found in {YearInSchool.names}')
assert val == YearInSchool.SOPHOMORE
Боюсь, что в Django не реализован метод, подобный get_FOO_display
(описанный здесь в doc) для достижения того, что вы хотите, но я думаю, что models.TextChoices
не предназначен для использования таким образом.
Например, POST-запрос должен напрямую содержать YearInSchool.FRESHMAN.value
вместо YearInSchool.FRESHMAN.label
(по крайней мере, это поведение по умолчанию в django.forms
), так что это не должно вас беспокоить.
Согласно этому, вот однострочное решение, которое вызовет сообщение ValueError
, если the_str
не найдено:
val = YearInSchool.values[YearInSchool.labels.index(the_str)]
И еще одно аналогичное решение, в два раза быстрее:
try:
val = next(filter(lambda x: x[1] == the_str, YearInSchool.choices))[0]
except StopIteration as err:
raise ValueError(f"{the_str} not found in {YearInSchool.labels}") from err