【问题标题】:Redefining imported jinja macros重新定义导入的 jinja 宏
【发布时间】:2014-10-27 07:22:27
【问题描述】:

假设我有这个带有宏的模板(这些是简化的):

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

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

这个包含覆盖

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

然后我想在同一个命名空间macros下拥有一个包含所有这些宏的模板

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

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

以及我期望的输出:

Overridden: foo
bar

但是b 是未定义的。我尝试将macros_override.html 模板更改为:

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

然后只导入覆盖模板作为宏,但在这种情况下宏a 没有被覆盖,我真的不知道为什么。

我可以以某种方式通过另一个导入覆盖 jinja 中导入的宏吗?

【问题讨论】:

    标签: jinja2


    【解决方案1】:

    所以在我同事的帮助下,我想通了。

    父模板在子模板之后评估
    http://jinja.pocoo.org/docs/dev/faq/#my-macros-are-overridden-by-something

    这意味着如果您想使用第二个选项,您只需检查宏是否存在于父模板中。

    像这样工作:

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

    这个包含覆盖

    {# 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 %}
    

    然后像这样导入它们

    {# template.html #}
    {% import 'macros_override.html' as macros %}
    
    {{ macros.a({ 'a': 'foo' }) }}
    {{ macros.b({ 'b': 'bar' }) }}
    

    它按预期输出

    Overridden: foo
    bar
    

    【讨论】:

      【解决方案2】:

      我们遇到了类似的问题,我们希望用户能够通过扩展默认模板来覆盖单个宏。重复 {% if not a %} 在这里有点乏味,所以我们用 Jinja2 扩展解决了这个问题:

      class DefaultMacroExtension(ext.Extension):
          """
          This extension provides a new `{% defaultmacro %}` statement, which defines a macro only if it does not exist.
          For example,
      
              {% defaultmacro example() %}
                  test 123
              {% enddefaultmacro %}
      
          is equivalent to
      
              {% macro default_example() %}
              test 123
              {% endmacro %}
              {% if not example %}
                  {% macro example() %}
                      test 123
                  {% endmacro %}
              {% endif %}
      
          The default implementation is also available as `default_$macroname`, which makes it possible
          to reference it in the override.
          """
      
          tags = {"defaultmacro"}
      
          def parse(self, parser):
              m = nodes.Macro(lineno=next(parser.stream).lineno)
              name = parser.parse_assign_target(name_only=True).name
              m.name = f"default_{name}"
              parser.parse_signature(m)
              m.body = parser.parse_statements(("name:enddefaultmacro",), drop_needle=True)
      
              if_stmt = nodes.If(
                  nodes.Not(nodes.Name(name, "load")),
                  [nodes.Macro(name, m.args, m.defaults, m.body)],
                  [],
                  [],
              )
              return [m, if_stmt]
      
      env = Environment(
          extensions=[DefaultMacroExtension],
      )
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-08-05
        • 2021-07-26
        • 2012-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多