Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redefining imported jinja macros

Tags:

jinja2

Let's say I have this template with macros (these are simplified):

{# macros.html #}
{% macro a(opts = {}) %}
   {{ opts.a }}
{% endmacro %}

{% macro b(opts = {}) %}
   {{ opts.b }}
{% endmacro %}

and this one which contains the override

{# macros_override.html #}
{% macro a(opts = {}) %}
    Overridden: {{ opts.a }}
{% endmacro %}

And then I want to have a template with all these macros under the same namespace macros

{# template.html #}
{% import 'macros.html' as macros %}
{% import 'macros_override.html' as macros %}

{{ macros.a({ 'a': 'foo' }) }}
{{ macros.b({ 'b': 'bar' }) }}

and the output I expect:

Overridden: foo
bar

But b is undefined. I tried to change macros_override.html template to be like this:

{# macros_override.html #}
{% extends 'macros.html' %}
{% macro a(opts = {}) %}
    Overridden: {{ opts.a }}
{% endmacro %}

and then import only override template as macros but macro a isn't overridden in this case and I don't really know why.

Can I override imported macro in jinja through another import somehow?

like image 783
vxsx Avatar asked Oct 27 '14 07:10

vxsx


1 Answers

So with the help of my colleague, I figured it out.

the parent template evaluated after the child one
http://jinja.pocoo.org/docs/dev/faq/#my-macros-are-overridden-by-something

that means if you want to use second option you just have to check the macro for existence in parent template.

Works like this:

{# macros.html #}
{% if not a %}
{% macro a(opts = {}) %}
   {{ opts.a }}
{% endmacro %}
{% endif %}

{% if not b %}
{% macro b(opts = {}) %}
   {{ opts.b }}
{% endmacro %}
{% endif %}

and this one which contains the override

{# macros_override.html #}
{% extends 'macros.html' %}
{% if not a %}{# I repeat here in case there's gonna be a double extend #}
{% macro a(opts = {}) %}
    Overridden: {{ opts.a }}
{% endmacro %}
{% endif %}

and the just import them like this

{# template.html #}
{% import 'macros_override.html' as macros %}

{{ macros.a({ 'a': 'foo' }) }}
{{ macros.b({ 'b': 'bar' }) }}

and it outputs as expected

Overridden: foo
bar
like image 161
vxsx Avatar answered Dec 07 '22 15:12

vxsx