我倾向于在不牺牲运行效率的情况下,以最紧凑和简洁的方式表达代码。
这是我的代码:
p_audio = plate.parts.filter(content__iendswith=".mp3")
p_video = not p_audio and plate.parts.filter(content__iendswith=".flv")
p_swf = not p_audio and not p_video and plate.parts.filter(content__iendswith=".swf")
extra_context.update({
'p_audio': p_audio and p_audio[0],
'p_video': p_video and p_video[0],
'p_swf': p_swf and p_swf[0]
})
是否有任何python / django大师可以大大缩短这段代码?
答案 0 :(得分:3)
实际上,在追求紧凑性和效率的过程中,您已经设法提出了非常低效的代码。这是因为当您引用p_audio
或not p_audio
时,会导致对该查询集进行评估 - 并且因为您之前没有对其进行切片,这意味着整个过滤器都来自数据库 - 例如所有以mp3结尾的plate
个对象,依此类推。
在引用该查询的值之前,应确保首先为每个查询执行切片。由于您关心代码紧凑性,您可能希望首先使用[:1]
进行切片,以获取单个对象的查询集:
p_audio = plate.parts.filter(content__iendswith=".mp3")[:1]
p_video = not p_audio and plate.parts.filter(content__iendswith=".flv") [:1]
p_swf = not p_audio and not p_video and plate.parts.filter(content__iendswith=".swf")[:1]
其余的可以保持不变。
编辑添加因为您只对每个列表的第一个元素感兴趣,因为您只将[0]
从每个元素传递到上下文中。但是在你的代码中,not p_audio
引用原始的,未剪切的查询集:并且为了确定qs的真/假值,Django必须对它进行评估,它从数据库中获取所有匹配的元素并将它们转换为Python对象。由于您实际上并不想要这些对象,因此您需要做的工作量超出您的需要。
请注意,它并没有重新运行每个时间:这是第一次,因为在第一次评估之后,查询集在内部进行缓存。但正如我所说,这已经比你想要的更多了。
答案 1 :(得分:2)
除了减少冗余之外,使用新内容类型也更容易扩展。
kinds = (("p_audio", ".mp3"), ("p_video", ".flv"), ("p_swf", ".swf"))
extra_context.update((key, False) for key, _ in kinds)
for key, ext in kinds:
entries = plate.parts.filter(content__iendswith=ext)
if entries:
extra_context[key] = entries[0]
break
答案 2 :(得分:0)
只是将此作为另一个答案添加灵感来自Pyroscope的上述(因为我的编辑必须经过同行评审)
最新的化身是利用Django模板系统在引用时忽略了不存在的上下文项,因此下面的mp3等不需要初始化为False(或0)。因此,以下内容符合OP代码的所有功能。另一个优化是mp3等用作键名(而不是“p_audio”等)
for key in ['mp3','flv','swf'] :
entries = plate.parts.filter(content__iendswith=key)[:1]
extra_context[key] = entries and entries[0]
if extra_context[key] :
break