I am looking for a way to have a Jinja macro that calls different implementations depending on the type of object that is being passed. Basically, standard Python method polymorphism. Right now, I’m using an ugly workaround similar to this:
{% macro menuitem(obj) %}
{% set type = obj.__class__.__name__ %}
{% if type == "ImageMenuItem" %}
{{ imagemenuitem(obj) }}
{% elif type == "FoobarMenuItem" %}
{{ foobarmenuitem(obj) }}
{% else %}
{{ textmenuitem(obj) }}
{% endif %}
{% endmacro %}
In pure Python, one can muck around with the module environment, e.g. globals()[x+'menuitem'], which isn’t pretty but works very well. I’ve tried something similar using the Jinja context, but the latter doesn’t seem to contain the macro definitions.
What better ways are there to achieve what I’m seeking?
I have now solved my problem similarly to how fabrizioM suggested, with one notable difference: Since the menu item presentation can (and most of the time, does) contain HTML, I don’t want mess around with HTML markup directly in the
presentmethods. So I ended up implementing the menu definitions in Python, the presentation in Jinja, with mutual recursion bridging the gap.Different types of menu items are represented by different subclasses:
The
macromapreferenced above is a dict mapping the type of menu item to the macro implementing its represenation. It’s all defined in Jinja:The actual menu definitions are cleanly expressed as trees of
MenuItemsubclasses:To kick off the presentation, a template has to call the top level section’s
presentmethod, passing a macro map to specify how to present the menu, e.g.main_menu.present(default_map). As can best be seen in theSectionmacro, menu items can then ask their children to present themselves, whosepresentmethod will call yet another Jinja macro, and so on, recursively.Having to explicitly pass around the macro map is not very pretty, but it grants a valuable benefit: One can now easily render different representations of the menu data without touching the menu definitions at all. For example, macro maps may be defined to render the main website menu, or a variant for mobile devices (in case CSS doesn’t suffice), or an XML sitemap, or even a plain text version. (We actually ended up using this system for the website menu and sitemap cases.)