如何在Django模板中访问枚举类型

时间:2016-03-12 02:43:20

标签: python django enums django-templates

我遇到了一个问题,无论我做什么,我都无法访问我的Django模板中的IntEnum(来自enum34 lib)。

我能够通过将其转换为词典来解决它:

def get_context_data(self, **kwargs):
    context = super(MyView, self).get_context_data(**kwargs)
    # Django templates don't play nice with Enums
    context['DEMOS'] = {d.name: d for d in DEMOS}
    # `context['DEMOS'] = DEMOS` doesn't work
    return context

当DEMO是IntEnum时这些不起作用,但是当DEMO转换为dict时这样做:

{{ DEMO.FOO }}  # outputs nothing
{{ DEMO.FOO|default_if_none:'foo' }}  # outputs nothing
{{ DEMO.FOO.value }}  # outputs nothing
{% if DEMO.FOO == 1 %}  # no matter what I compare to, always False

任何想法为什么?这是一个已知的问题吗?

2 个答案:

答案 0 :(得分:9)

再挖掘一下,我找到了答案。

来自the website

  

从技术上讲,当模板系统遇到一个点时,它会按以下顺序尝试以下查找:

     

字典查找

     

属性或方法查找

     

数字索引查找

     

如果结果值是可调用的,则调用它时不带参数。调用的结果成为模板值。

最后一行应该说:

  

如果任何结果/中间值可以调用,......

逐步完成该过程:

  • 'DEMOS'中查找context,获取<enum 'DEMOS'>

  • 检查它是否可调用(确实如此)

  • 不带参数调用

  • 获得TypeError

所以问题是Enum类是可调用的,模板系统会尝试调用它,这会引发错误并中止(返回一个空字符串:'')。

但是,有一种方法可以解决这个问题。 django.templates.base的通话代码包含以下内容 保护条件:

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

代码检查名为do_not_call_in_templates的属性,如果True,它将跳过调用部分,这应解决问题。

使用Python Enum(或enum34 backport),最简单的方法是使用装饰器。如果Django没有用于此目的,你可以轻松地自己动手:

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

然后装饰你的Enum

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

附加属性不会干扰您的设置 枚举常量,因为枚举在定义后是固定的。

答案 1 :(得分:2)

使用Django&#39; Enum您可以使用__members__属性:

context['DEMOS'] = DEMOS.__members__

Reference