use*_*171 66 python django loops
import collections
data = [
{'firstname': 'John', 'lastname': 'Smith'},
{'firstname': 'Samantha', 'lastname': 'Smith'},
{'firstname': 'shawn', 'lastname': 'Spencer'},
]
new_data = collections.defaultdict(list)
for d in data:
new_data[d['lastname']].append(d['firstname'])
print new_data
Run Code Online (Sandbox Code Playgroud)
这是输出:
defaultdict(<type 'list'>, {'Smith': ['John', 'Samantha'], 'Spencer': ['shawn']})
Run Code Online (Sandbox Code Playgroud)
这是模板:
{% for lastname, firstname in data.items %}
<h1> {{ lastname }} </h1>
<p> {{ firstname|join:", " }} </p>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)
但是我的模板中的循环不起作用.什么都没有出现.它甚至没有给我一个错误.我怎样才能解决这个问题?它应该显示姓氏和名字,如下所示:
<h1> Smith </h1>
<p> John, Samantha </p>
<h1> Spencer </h1>
<p> shawn </p>
Run Code Online (Sandbox Code Playgroud)
Séb*_*ier 84
完成插入新值后,可以通过禁用defaultdict的默认功能来避免复制到新的dict :
new_data.default_factory = None
Run Code Online (Sandbox Code Playgroud)
说明
将在Django模板变量解析算法将尝试解析new_data.items
为new_data['items']
第一,使用时其解析为一个空列表defaultdict(列表).
要禁用默认为空列表并让Django失败,new_data['items']
然后继续解析尝试直到调用new_data.items()
,defaultdict的default_factory属性可以设置为None.
vir*_*ilo 41
尝试:
dict(new_data)
Run Code Online (Sandbox Code Playgroud)
而在Python 2中,最好使用iteritems
而不是items
:)
由于“问题”在多年后仍然存在并且是 Django 模板工作方式的固有特性,我更喜欢写一个新的答案,详细说明为什么这种行为保持原样。
首先,解决方案是在将其传递给模板上下文之前将其defaultdict
转换为 a dict
:
context = {
'data': dict(new_data)
}
Run Code Online (Sandbox Code Playgroud)
你不应该defaultdict
在 Django 的模板上下文中使用对象。
此“错误”背后的原因在以下Django 问题 #16335 中有详细说明:
事实上,这归结为模板语言使用相同的语法进行字典和属性查找的事实。
...从文档中:
字典查找、属性查找和列表索引查找是用点表示法实现的。[...] 如果变量解析为可调用对象,模板系统将不带参数调用它,并使用其结果而不是可调用对象。
当 Django 解析你的模板表达式时,它会先尝试data['items']
。但是,这是一个有效的表达式,它将自动items
在您的 defaultdict 中创建一个新条目data
,使用空列表(在原始作者情况下)进行初始化并返回创建的列表(空)。
预期的操作是调用items
没有实例参数的方法data
(简而言之:)data.items()
,但由于data['items']
是一个有效的表达式,Django 停在那里并获取刚刚创建的空列表。
如果您尝试使用相同的代码,但使用data = defaultdict(int)
,您将得到TypeError: 'int' object is not iterable
,因为 Django 将无法迭代创建defaultdict
.