'How to use custom labels from Django models.Choices field together with enum.auto?
Before Django v3.0 I used to use enum.Enum together with enum.auto (see reference) for my choices fields. The reason was mostly so I could use my enumeration class for type hints and auto enforced the usage of the enumeration class instead of using the constant value in code. However Django v3.0+ introduced the enumeration types which is similar to the enum module but with some interesting features. I'd like to use it together with enum.auto but wasn't able so far.
The further I got was to something like this:
class MyChoices(models.IntegerChoices, Enum):
FIRST = auto()
SECOND = auto()
THIRD = auto()
The enumeration values and the auto-generated labels are correct:
MyChoices
Out[13]: <enum 'MyChoices'>
MyChoices.choices
Out[14]: [(1, 'First'), (2, 'Second'), (3, 'Third')]
MyChoices.labels
Out[15]: ['First', 'Second', 'Third']
MyChoices.values
Out[16]: [1, 2, 3]
MyChoices.FIRST
Out[17]: <MyChoices.FIRST: 1>
The issue is when I try to define custom labels:
class MyChoices(models.IntegerChoices, Enum):
FIRST = auto(), '1st'
SECOND = auto(), '2nd'
THIRD = auto(), '3rd'
Traceback (most recent call last):
File "/usr/local/lib/python3.8/site-packages/IPython/core/interactiveshell.py", line 3441, in run_code
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-20-cf882f261e5f>", line 1, in <module>
class MyChoices(models.IntegerChoices, Enum):
File "/usr/local/lib/python3.8/site-packages/django/db/models/enums.py", line 28, in __new__
cls = super().__new__(metacls, classname, bases, classdict, **kwds)
File "/usr/local/lib/python3.8/enum.py", line 219, in __new__
enum_member = __new__(enum_class, *args)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'auto'
I suppose the issue is something conflicting with the inherited Enum class. I tried removing it but then auto() doesn't work properly. Does anyone have any ideas about how to make it work?
Update: I noticed the Enum is not required in my class in order to auto() work. My enumeration works without it with the auto-generated labels but it still doesn't work with custom labels.
Solution 1:[1]
I found out this is not possible without a patch to Django enumeration type. The exception described above occurs because the auto value is not solved by the time this piece of code is called, so it tries to use int to convert an auto instance. This only happens when the enumeration is a tuple, i.e. auto() and a label, because of this piece of code in _EnumDict.__setitem__ (enum module):
elif not _is_descriptor(value):
if key in self:
# enum overwriting a descriptor?
raise TypeError('%r already defined as: %r' % (key, self[key]))
if isinstance(value, auto):
if value.value == _auto_null:
value.value = self._generate_next_value(key, 1, len(self._member_names), self._last_values[:])
self._auto_called = True
value = value.value
This is OK when the enumeration is only auto but doesn't work when declared together with a label because value is a tuple. This is not an issue with the enum module itself because it doesn't expect tuples.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Diogo M. Santana |
