从从JSON导入的对象列表(dict)获取字段列表

时间:2019-07-09 08:35:11

标签: python jinja2

来自此json:

{
  "obj": [
    {
      "int": 0
    },
    {
      "int": 1
    }
  ]
}

我想获取字段int的{​​{1}}属性的列表,以便可以对该列表进行汇总,例如使用Jinja2语法取objint的平均值。

我尝试将过滤器objselectattr("int")过滤器结合使用,但得到+的'不受支持的操作数类型:'int'和'dict'。

我正在使用Jinja2和sum从模板生成docx文件。

docxtpl

docx模板包含一行:

import json
j = '{"obj": [{"int": 0},{"int": 1}]}'
context = json.loads(j)

from docxtpl import DocxTemplate
import jinja2

tpl = DocXtemplate('template.docx')
tpl.render(context, jinja_env)
tpl.save('out.docx')

我想像上面一样尝试在求和时在doxc文件中看到{{obj|selectattr("int")|sum}} ,我也希望能够得出均值并最终在其他操作中重用它。

>

编辑:作为对那些我应该在python中执行此操作的回答:

我正在开发一种用于从数据库和模板文件生成docx报告的工具。该工具的第一部分是一个C ++程序,该程序从数据库生成json数据。第二部分是使用Jinja2从模板生成docx格式的报告的脚本。我希望用户仅弄乱模板,而不必修改脚本,我也希望具有某种模块化,并能够计算json树上的聚合。由于Jinja2在列表和其他类型的操作上提供了1,因此我认为它可以增加另一层模块化,而无需编写更多代码。目前,我已经为用户增加了在json树上进行聚合并将其插入节点树的可能性,但是我的解决方案并不完美,其代价是提供了另一个模板文件以进行数据生成,这使得工具更复杂。

我希望现在更有意义,为什么我不想在脚本中这样做。

Edit2 :一个稍微复杂的示例:

sum

我希望能够做类似的事情:

{
    "arr": [
        {
            "obj": [
                {
                    "name": 0
                },
                {
                    "name": 1
                }
            ]
        },
        {
            "obj": [
                {
                    "name": 0
                },
                {
                    "name": 1
                }
            ]
        }
    ]
}

更好的解决方案将是可以直接在Jinja2中进行列表扩展:

{{arr|get_attr_list('obj')|get_attr_list('int')}}

3 个答案:

答案 0 :(得分:3)

这绝对不是您在Jinja中应该做的事情。这是用于显示内容的模板语言。

您应该在Python中做到这一点,这是一个简单的单行代码:

sum(item["int"] for item in context["obj"])

答案 1 :(得分:0)

这里

d= {
  "obj": [
    {
      "int": 0
    },
    {
      "int": 1
    }
  ]
}
# create a list
lst = [e['int'] for e in d['obj']]
print(lst)
# now you can do stats on this list
import statistics
mean = statistics.mean(lst)
print(mean)

答案 2 :(得分:0)

完整的答案适用于简单和稍微复杂的示例:

我可以提供一个返回列表的过滤器,为了构成它,我应该检查感兴趣的字段是否是列表,如果是这样,我应该将结果展平。需要进一步定义边框大小写,但它可以起作用:

def get_list(value, arg):
  if type(value) is dict:
    return value[arg]
  elif type(value) is list:
    if len(value) == 0:
        return []
    else:
      res = [ x[arg] for x in value ]
      if type(res[0]) is list:
        res = list(itertools.chain(*res))
      return res
  else:
    return value

然后按预期工作:

第一个示例

{{ obj|get_list("int")|sum }}

(输出1)

第二个示例

{{ arr|get_list("obj")|get_list("int")|sum }}

(输出2)