在Jinja2中合并任意深度的dicts

时间:2014-09-09 21:00:00

标签: jinja2

如何递归合并Jinja2中的dicts而无需定义自定义过滤器?

所以

  { a: { b: 'ab', d: 'ad'          } }
+ { a: { b: 'aX',          e: 'ae' } }

变为

  { a: { b: 'aX', d: 'ad', e: 'ae' } }

我正在将一些Mako模板迁移到Jinja2。使用Mako我可以简单地使用一个小的python代码片段为我做这个......我不能使用自定义过滤器的原因是,我根本无法在模板引擎中注册自定义过滤器,因为我无法直接访问它。

2 个答案:

答案 0 :(得分:2)

我终于找到了解决问题的方法:

{%- macro deep_merge(a, b): %}
  {%- for k,v in b.items(): %}
    {%- if v is not defined: %}
      {%- do a.pop(k) %}
    {%- else: %}
      {%- if v is mapping: %}
        {%- if a[k] is not mapping: %}
          {%- do a.update({ k: { } }) %}
        {%- endif %}
        {%- do deep_merge(a[k], v) %}
      {%- else: %}
        {%- do a.update({ k: v }) %}
      {%- endif %}
    {% endif %}
  {%- endfor %}
{%- endmacro %}

{%- do deep_merge(a, b) %}

这段Jinja2-Code递归地将b合并到a中,覆盖重复键(b优先)并从a中删除设置为{{}的键1}} null

答案 1 :(得分:1)

这很难看,但听起来你的情况有点Abby Normal

{# Untested code - may not work #}
{% macro merge(destination) %}
{% for provider in varargs %}
    {% for key, value in provider.items() %}
        {% if value is mapping %}
            {% set intermediate = {} %}
            {% do merge(intermediate, destination.get(key, {}), value) %}
            {% do destination[key] = intermediate %}
        {% else %}
            {% do destination[key] = value %}
        {% endif %}
    {% endfor %}
{% endfor %}
{% endmacro %}

你可以像这样使用它:

{% set result = {} %}
{% do merge(result, first_values, second_values) %}
{# result is now the merger of first_values and second_values #}