Django的模板语言无法安全地处理dict

时间:2016-05-11 10:16:28

标签: python django django-templates

在django的模板语言中,如果变量名为a.x,那么django将按此顺序尝试以获得正确的值:

  1. a['x'],字典查找
  2. a.xa.x(),属性或方法查找
  3. a[x],列出索引
  4. 结果是:任何支持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']的类型。

    所以我的问题是,为什么订单是这样设计的,以及如何使其安全。

3 个答案:

答案 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

相关问题