[Django]-How to access Enum types in Django templates

28👍

A little more digging and I found the answer.

From Django’s templates documentation:

Technically, when the template system encounters a dot, it tries the following lookups, in this order:

Dictionary lookup

Attribute or method lookup

Numeric index lookup

If the resulting value is callable, it is called with no arguments. The result of the call becomes the template value.

That last line should say:

If any of the resulting/intermediate values is callable, …

Stepping through that process:

  • lookup 'DEMOS' in the context, get <enum 'DEMOS'>

  • check if it is callable (it is)

  • call it with no arguments

  • get a TypeError

So the problem is that an Enum class is callable, and the templating system will try to call it, which will raise an error and abort (returning an empty string: '').

However, there is a way around that problem.
django.templates.base‘s calling code contains the following
guard condition:

if getattr(current, 'do_not_call_in_templates', False):
    pass

The code checks for an attribute called do_not_call_in_templates, and if True then it will skip the call portion, which should solve the problem.

Using Python’s Enum (or the enum34 backport) the simplest way will be to use a decorator. If Django doesn’t already have one for this purpose, you can roll your own easily enough:

def forDjango(cls):
    cls.do_not_call_in_templates = True
    return cls

and then decorate your Enum:

@forDjango
class DEMOS(Enum):
    eggs = 'runny'
    spam = 'hard'
    cheese = 'smelly'

The additional attribute does not interfere with your set of
Enum constants, because Enums are fixed once defined.

11👍

Using Django’s Enum you can use __members__ property:

context['DEMOS'] = DEMOS.__members__

Reference

Leave a comment