Jinja: 无法使用“items”元素迭代对象

创建于 2017-01-09  ·  10评论  ·  资料来源: pallets/jinja

服务器正在返回此 JSON:
{
“项目”:[1,2,3]
...
}

尝试迭代“项目”会产生:
{% for el in data.items %}
....
类型错误:'builtin_function_or_method' 对象不可迭代

发生上述情况是因为 Python dict 有一个内置函数“items()”。

作为临时工。 解决方法,我安装了一个钩子并将 JSON 响应中的键从“items”重命名为“__items”,然后将其传递给 Jinja2。 那时,我正在迭代重命名的属性:
{% for el in data.__items %}

理想情况下,Jinja2 应该忽略 for 循环或 if 语句中的内置函数,除非专门使用 function() 符号调用。

最有用的评论

您可以使用{% for el in data['items'] %}来确定项目的优先级。 这也包含在文档中。 http://jinja.pocoo.org/docs/2.9/templates/#variables

所有10条评论

您可以使用{% for el in data['items'] %}来确定项目的优先级。 这也包含在文档中。 http://jinja.pocoo.org/docs/2.9/templates/#variables

如果 JSON 响应偶尔不包含“项目”(假设它是响应的可选属性),它将失败。 在这种情况下, {% for el in data['items'] %} 也会产生:
类型错误:'builtin_function_or_method' 对象不可迭代

...因为始终定义项目(作为内置函数)。

这是一个错误,IMO。 data['items'] 不应该与内置函数发生冲突。 换句话说,如果你想干净地迭代一个可选的“items”属性,你必须重命名它。 理想情况下,情况不应该如此。

为什么 JSON 响应不包含项目? 我不完全确定我在这里看到了问题。 当然,您提前知道您的数据是什么。 您还可以在模板中使用in运算符在字典中检查键。

改变这种行为是完全不可能的,因为如果我们删除这个属性/项目支持,成千上万的模板会被破坏。

我不建议放弃任何东西,只是为了让它更严格。

今天的问题是,当您使用显式查找符号时: data['items']它会找到一个内置字典函数,而它不应该。 Python 不会这样做,jinja 也不应该这样做。 如果需要调用内置函数(或任何与此相关的函数),您可以使用调用符号: data.items()

不确定那里的特殊情况dict.items是否很清楚。 特别是因为它仍然无法用于自定义类似 dict 的类型,甚至OrderedDict 。 我认为在这些情况下foo['items']更好。 这不是超级漂亮但一致的行为。

我可以想象以更好的方式解决这个问题的唯一可能的“修复/破解”是检查是否在迭代中使用了普通属性(即不是函数调用),并且您正在尝试迭代不可迭代但可调用的东西. 在这种情况下,尝试该项目不太可能破坏任何现有代码。 然而,在 Jinja 中这种行为的实现可能会非常糟糕;)

为什么这是一个特例? 我要求 Jinja 的行为与 Python 完全一样。 具体来说,如果 foo['items'] 中没有用户插入的键“items”,则应该产生 None 。 今天,Jinja 回过头来寻找同名的内置函数。 所以简单地做 Python 所做的:

>>> print {}.get('items')
None

顺便说一句,我也相信替代符号“foo.items”也应该处理得很好,因为你需要使用“()”来调用一个可调用的,但是如果你需要 foo.items 的一些向后兼容性来找到一个键或自动调用一个函数,那么我想那太糟糕了。

['x'] 和.x的 Jinja 逻辑是这样的:

  • 检查 item/attr(无论您在 Python 中获得什么语法)是否存在,如果是,请使用它
  • 检查 attr/item(与您的语法在 Python 中所做的“相反”)是否存在,如果存在,请使用它
  • 如果两者都不存在则失败

所以x.items检查属性,因为存在它使用它。 无论比赛如何,这种逻辑都是如此。 改进这将需要属性查找逻辑根据其上下文进行更改。 即便如此,它也会导致像这段代码这样的尴尬情况:

{% for x in mydict.items %}

vs 这段代码不起作用

{% set items = mydict.items %}
{% for x in items %}

如果不跟踪变量的来源,在这种情况下保持特殊处理是不可能的。

@slisznia您实际上是在要求 Jinja2 彻底改变目前已经使用了大约 7 年的属性查找系统。

啊,我什至没有看到foo['bar']不进行属性查找的建议。 这肯定是个坏主意! 你只是使用for item in data.get('items', [])什么问题?

@ThiefMaster mydict.get('items', [])当然有效,感谢您指出除重命名键之外的另一种方法。

此页面是否有帮助?
0 / 5 - 0 等级