在django的模板语言中,如果变量名为a.x
,那么django将按此顺序尝试以获得正确的值:
a['x']
,字典查找a.x
或a.x()
,属性或方法查找a[x]
,列出索引结果是:任何支持var['str']
的变量都会成为定时炸弹。想象一下,a
是一个dict
,其中一个关键'项'的值是'hello world',然后a.items
将导致'hello world',而不是ditc.items()
。这是代码:
from django.template import Engine, Context
template = """
{% for k, v in a.items %}
{{ k }} = {{ v }}
{% endfor %}
"""
e = Engine()
t = e.from_string(template)
a = {'items': 'hello world'}
print(t.render(Context({'a': a})))
虽然我希望items = hello world
作为输出,但实际输出是:
h =
e =
l =
...
对于dict变量,如果它具有与dict方法名称相同的键,则您将永远无法在模板中调用该方法。它变成了一颗定时炸弹,因为你永远不知道将来你是否会将一个名为'items'的键添加到一个dict变量中。
这种风险不仅适用于dict,也适用于任何接受var['key']
的类型。
所以我的问题是,为什么订单是这样设计的,以及如何使其安全。
答案 0 :(得分:2)
有一个简单的解决方法(除了为密钥使用更好的名称):
from django.template import Engine, Context
template = """
{% for k, v in items_func %}
{{ k }} = {{ v }}
{% endfor %}
"""
e = Engine()
t = e.from_string(template)
a = {'items': 'hello world'}
print(t.render(Context({'a': a, 'items_func': a.items})))
>> items = hello world
答案 1 :(得分:2)
为什么订单设计如此
它的设计是这样的,因为模板语法应该很简单,这样做可以鼓励你将更多的逻辑放入视图而不是模板中。
如何确保安全?
为您的密钥指定一个描述性名称
"项目"并没有做任何事情来实际描述密钥内部的内容,因此它不仅会给django带来麻烦,而且还会让任何其他需要调试此字典问题的开发人员头疼。
答案 2 :(得分:2)
通过将export_excel.php
用于三种不同的查找,总是存在这样的问题的可能性。如果订单已更改为首先尝试.
,则会导致其他想要访问a.x
的用户出现问题。
我认为没有一种通用的方法可以防止这种行为。一旦你被它烧了一次,你就会记得以后不要在你的词典中加上a['x']
键。
作为最后的手段,您可以切换到Jinja,它支持下标语法items
。这意味着{{ foo['bar'] }}
首先检查属性{{ foo.bar }}
。有关详细信息,请参阅Jinja docs。