我遇到了一个问题,无论我做什么,我都无法访问我的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
任何想法为什么?这是一个已知的问题吗?
答案 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)