summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Pope <nick@nickpope.me.uk>2021-02-19 17:17:11 +0000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2021-03-24 07:45:33 +0100
commita96c730431196b119559bbb18a0e85e6ee8b2597 (patch)
tree5cc8c42ed5fc8fe9d72851617541f184ae4b99ed
parent41e39c41c9225bc3cbd5f333694e0a4d113136be (diff)
Fixed #32460 -- Allowed "label"/"do_not_call_in_templates" members in model choice enums.
-rw-r--r--django/db/models/enums.py17
-rw-r--r--tests/model_enums/tests.py20
2 files changed, 31 insertions, 6 deletions
diff --git a/django/db/models/enums.py b/django/db/models/enums.py
index f04698b9f6..7082a397c2 100644
--- a/django/db/models/enums.py
+++ b/django/db/models/enums.py
@@ -1,4 +1,5 @@
import enum
+from types import DynamicClassAttribute
from django.utils.functional import Promise
@@ -26,12 +27,8 @@ class ChoicesMeta(enum.EnumMeta):
# assignment in enum's classdict.
dict.__setitem__(classdict, key, value)
cls = super().__new__(metacls, classname, bases, classdict, **kwds)
- cls._value2label_map_ = dict(zip(cls._value2member_map_, labels))
- # Add a label property to instances of enum which uses the enum member
- # 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
+ for member, label in zip(cls.__members__.values(), labels):
+ member._label_ = label
return enum.unique(cls)
def __contains__(cls, member):
@@ -62,6 +59,14 @@ class ChoicesMeta(enum.EnumMeta):
class Choices(enum.Enum, metaclass=ChoicesMeta):
"""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):
"""
Use value when cast to str, so that Choices set as model instance
diff --git a/tests/model_enums/tests.py b/tests/model_enums/tests.py
index 3bfec1596a..78f8b146be 100644
--- a/tests/model_enums/tests.py
+++ b/tests/model_enums/tests.py
@@ -159,6 +159,26 @@ class ChoicesTests(SimpleTestCase):
with self.assertRaises(AttributeError):
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):
FS = b'\x1c', 'File Separator'