我正在寻找一种方法来使用一个Jinja宏来调用不同的实现,具体取决于传递的对象的类型。基本上,标准的Python方法多态。现在,我正在使用类似于此的丑陋解决方法:
{% macro menuitem(obj) %}
{% set type = obj.__class__.__name__ %}
{% if type == "ImageMenuItem" %}
{{ imagemenuitem(obj) }}
{% elif type == "FoobarMenuItem" %}
{{ foobarmenuitem(obj) }}
{% else %}
{{ textmenuitem(obj) }}
{% endif %}
{% endmacro %}
在纯Python中,可以使用模块环境,例如: globals()[x+'menuitem']
,这不是很漂亮,但效果很好。我使用Jinja上下文尝试了类似的东西,但后者似乎没有包含宏定义。
有什么更好的方法来实现我所寻求的目标?
答案 0 :(得分:7)
OOP的本质:多态性。
Create a presentation Layer for your objects:
class MenuPresentation:
def present(self):
raise NotImplementedException()
class ImageMenuPresentation(MenuPresentation):
def present(self):
return "magic url "
class TextMenuPresentation(MenuPresentation):
def present(self):
return "- text value here"
然后只是一个问题:
{% macro menuitem(obj) %}
{{ obj.present() }}
{% endmacro %}
答案 1 :(得分:2)
我现在已经解决了我的问题,类似于fabrizioM的建议,但有一个值得注意的区别:由于菜单项演示可以(并且大部分时间都是)包含HTML,我不希望直接在HTML标记中乱搞present
方法。所以我最终在Python中实现了菜单定义,Jinja中的表示,相互递归缩小了差距。
不同类型的菜单项由不同的子类表示:
class MenuItem(object):
def present(self, macromap):
return macromap[type(self).__name__](self, macromap)
class TextLink(MenuItem):
def __init__(self, url, text):
self.url, self.text = url, text
class Section(MenuItem):
def __init__(self, text, items):
self.text, self.items = text, items
class ImageLink(MenuItem):
...
上面引用的macromap
是一个dict,它将菜单项的类型映射到实现其表示的宏。这一切都在Jinja中定义:
{% macro TextLink(l, macromap) %}
<a class="menuitem" href="{{l.url|escape}}">
{{ l.text|escape }}
</a>
{% endmacro %}
{% macro Section(s, macromap) %}
<div class="heading">{{s.text}}</div>
<ul class="items">
{% for item in s.items %}
<li>{{ item.present(macromap) }}</li>
{% endfor %}
</ul>
{% endmacro %}
{% set default_map = {'TextLink': TextLink, 'Section': Section, ...}
实际的菜单定义干净地表示为MenuItem
子类的树:
main_menu = section("Main Menu", [
section("Product Line 1", [
TextLink("/products/...", "A product"),
...
]),
section(...),
])
要启动演示文稿,模板必须调用顶级部分的present
方法,传递宏地图以指定如何呈现菜单,例如main_menu.present(default_map)
。最好在Section
宏中看到,菜单项可以让他们的孩子展示自己,present
方法将调用另一个Jinja宏,依此类推,递归。
必须明确地传递宏地图并不是很漂亮,但它带来了一个有价值的好处:现在可以轻松地呈现菜单数据的不同表示而根本不触及菜单定义。例如,可以定义宏映射以呈现主网站菜单,或者移动设备的变体(在CSS不足的情况下),或XML站点地图,或甚至纯文本版本。 (实际上,我们最终将此系统用于网站菜单和站点地图案例。)