Fixed #32460 -- Allowed "label"/"do_not_call_in_templates" members in model choice enums.
This commit is contained in:
parent
41e39c41c9
commit
a96c730431
|
@ -1,4 +1,5 @@
|
||||||
import enum
|
import enum
|
||||||
|
from types import DynamicClassAttribute
|
||||||
|
|
||||||
from django.utils.functional import Promise
|
from django.utils.functional import Promise
|
||||||
|
|
||||||
|
@ -26,12 +27,8 @@ class ChoicesMeta(enum.EnumMeta):
|
||||||
# assignment in enum's classdict.
|
# assignment in enum's classdict.
|
||||||
dict.__setitem__(classdict, key, value)
|
dict.__setitem__(classdict, key, value)
|
||||||
cls = super().__new__(metacls, classname, bases, classdict, **kwds)
|
cls = super().__new__(metacls, classname, bases, classdict, **kwds)
|
||||||
cls._value2label_map_ = dict(zip(cls._value2member_map_, labels))
|
for member, label in zip(cls.__members__.values(), labels):
|
||||||
# Add a label property to instances of enum which uses the enum member
|
member._label_ = label
|
||||||
# that is passed in as "self" as the value to use when looking up the
|
|
||||||
# label in the choices.
|
|
||||||
cls.label = property(lambda self: cls._value2label_map_.get(self.value))
|
|
||||||
cls.do_not_call_in_templates = True
|
|
||||||
return enum.unique(cls)
|
return enum.unique(cls)
|
||||||
|
|
||||||
def __contains__(cls, member):
|
def __contains__(cls, member):
|
||||||
|
@ -62,6 +59,14 @@ class ChoicesMeta(enum.EnumMeta):
|
||||||
class Choices(enum.Enum, metaclass=ChoicesMeta):
|
class Choices(enum.Enum, metaclass=ChoicesMeta):
|
||||||
"""Class for creating enumerated choices."""
|
"""Class for creating enumerated choices."""
|
||||||
|
|
||||||
|
@DynamicClassAttribute
|
||||||
|
def label(self):
|
||||||
|
return self._label_
|
||||||
|
|
||||||
|
@property
|
||||||
|
def do_not_call_in_templates(self):
|
||||||
|
return True
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""
|
"""
|
||||||
Use value when cast to str, so that Choices set as model instance
|
Use value when cast to str, so that Choices set as model instance
|
||||||
|
|
|
@ -159,6 +159,26 @@ class ChoicesTests(SimpleTestCase):
|
||||||
with self.assertRaises(AttributeError):
|
with self.assertRaises(AttributeError):
|
||||||
models.TextChoices('Properties', 'choices labels names values')
|
models.TextChoices('Properties', 'choices labels names values')
|
||||||
|
|
||||||
|
def test_label_member(self):
|
||||||
|
# label can be used as a member.
|
||||||
|
Stationery = models.TextChoices('Stationery', 'label stamp sticker')
|
||||||
|
self.assertEqual(Stationery.label.label, 'Label')
|
||||||
|
self.assertEqual(Stationery.label.value, 'label')
|
||||||
|
self.assertEqual(Stationery.label.name, 'label')
|
||||||
|
|
||||||
|
def test_do_not_call_in_templates_member(self):
|
||||||
|
# do_not_call_in_templates is not implicitly treated as a member.
|
||||||
|
Special = models.IntegerChoices('Special', 'do_not_call_in_templates')
|
||||||
|
self.assertEqual(
|
||||||
|
Special.do_not_call_in_templates.label,
|
||||||
|
'Do Not Call In Templates',
|
||||||
|
)
|
||||||
|
self.assertEqual(Special.do_not_call_in_templates.value, 1)
|
||||||
|
self.assertEqual(
|
||||||
|
Special.do_not_call_in_templates.name,
|
||||||
|
'do_not_call_in_templates',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Separator(bytes, models.Choices):
|
class Separator(bytes, models.Choices):
|
||||||
FS = b'\x1c', 'File Separator'
|
FS = b'\x1c', 'File Separator'
|
||||||
|
|
Loading…
Reference in New Issue