如何通过Jinja2将Python中的列表传递给JavaScript

use*_*766 58 javascript python variables jinja2

假设我有一个Python变量:

list_of_items = ['1','2','3','4','5']
Run Code Online (Sandbox Code Playgroud)

我通过渲染HTML将它传递给Jinja,我还在JavaScript中使用了一个函数somefunction(variable).我试图通过每个项目list_of_items.我试过这样的事情:

{% for item in list_of_items %}
<span onclick="somefunction({{item}})">{{item}}</span><br>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

是否可以将列表从Python传递给JavaScript,还是应该在循环中逐个传递列表中的每个项目?我怎样才能做到这一点?

mde*_*ous 90

要将一些上下文数据传递给javascript代码,您必须以javascript(即JSON)"理解"的方式对其进行序列化.您还需要使用safeJinja过滤器将其标记为安全,以防止您的数据被htmlescaped.

你可以通过这样做来实现这一点:

风景

import json

@app.route('/')
def my_view():
    data = [1, 'foo']
    return render_template('index.html', data=json.dumps(data))
Run Code Online (Sandbox Code Playgroud)

模板

<script type="text/javascript">
    function test_func(data) {
        console.log(data);
    }
    test_func({{ data|safe }})
</script>
Run Code Online (Sandbox Code Playgroud)

编辑 - 确切的答案

因此,要实现您想要的内容(遍历项目列表并将其传递给javascript函数),您需要单独序列化列表中的每个项目.您的代码将如下所示:

风景

import json

@app.route('/')
def my_view():
    data = [1, "foo"]
    return render_template('index.html', data=map(json.dumps, data))
Run Code Online (Sandbox Code Playgroud)

模板

{% for item in data %}
    <span onclick=someFunction({{ item|safe }});>{{ item }}</span>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

编辑2

在我的例子中,我使用Flask,我不知道你正在使用什么框架,但你明白了,你必须使它适合你使用的框架.

编辑3(安全警告)

永远不要使用用户提供的数据,只能用可靠的数据做到这一点!

否则,您会将应用程序暴露给XSS漏洞!

  • 可能更好的是,不是作为JSON字符串传递而是执行`{{item | tojson | safe}}` (8认同)
  • -1; 在一般情况下,这会被破坏和不安全,并且只有少数情况下可以使用它。如果其中任何一项包含空格,则输出将被破坏,如果其中一项是 `" &gt;&lt;script&gt;alert('pwned');&lt;/script&gt; "` 那么你将被 XSS。是的,您有一个安全警告,但即便如此,这也是一个糟糕的答案;有一些干净的方法*不会*损坏(例如使用 Flask 的 `tojson` 过滤器),而应该使用这些方法。 (3认同)

God*_*ith 27

我使用Flask时遇到了类似的问题,但我不必诉诸JSON.我只是通过一个列表letters = ['a','b','c']render_template('show_entries.html', letters=letters)和设置

var letters = {{ letters|safe }}
Run Code Online (Sandbox Code Playgroud)

在我的JavaScript代码中.Jinja2替换{{ letters }}['a','b','c'],其中javascript被解释为字符串数组.

  • -1; 这不适用于所有值,并且如果用户提供了任何内容,则很危险。例如,如果列表中的字符串之一是“ &lt;/ script&gt; &lt;script&gt; alert('pwned')&lt;/ script&gt;`,那么它将破坏您的页面。 (3认同)

Mar*_*ery 14

你可以用 Jinja 的tojson过滤器来做到这一点,它

将结构转储到 JSON,以便<script>在 HTML 中的任何位置的标签 [和] 中使用都是安全的,但双引号属性除外。

例如,在您的 Python 中,编写:

some_template.render(list_of_items=list_of_items)
Run Code Online (Sandbox Code Playgroud)

...或者,在 Flask 端点的上下文中:

return render_template('your_template.html', list_of_items=list_of_items)
Run Code Online (Sandbox Code Playgroud)

然后在你的模板中,写下这个:

{% for item in list_of_items %}
<span onclick='somefunction({{item | tojson}})'>{{item}}</span><br>
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

(请注意,该onclick属性是引号。这是必要的,因为在其输出中|tojson转义'字符而不是"字符,这意味着它可以安全地用于单引号 HTML 属性中,但不能用于双引号属性。)

或者,要list_of_items在内联脚本中使用而不是 HTML 属性,请编写以下内容:

<script>
const jsArrayOfItems = {{list_of_items | tojson}};
// ... do something with jsArrayOfItems in JavaScript ...
</script>
Run Code Online (Sandbox Code Playgroud)

不要json.dumps在 Python 代码中使用JSON 编码变量并将生成的 JSON 文本传递给模板。这会为某些字符串值产生不正确的输出,并且如果您尝试对用户提供的值进行编码,则会将您暴露给 XSS。这是因为 Python 的内置json.dumps不会转义像<>这样的字符(需要转义以安全地将值模板化为 inline <script>s,如https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for 所述-contents-of-script-elements)或单引号(需要转义以安全地将值模板化为单引号 HTML 属性)。

如果您使用 Flask,请注意 Flask 注入自定义tojson过滤器而不是使用 Jinja 的版本。但是,上面写的所有内容仍然适用。这两个版本的行为几乎相同;Flask 只允许一些在 Jinja 版本中不可用的特定于应用程序的配置

  • 这个答案似乎比所选答案更好。 (2认同)

Syl*_*are 7

为了补充所选的答案,我一直在测试一个新选项,该选项也使用 jinja2 和 Flask 工作:

@app.route('/')
def my_view():
    data = [1, 2, 3, 4, 5]
    return render_template('index.html', data=data)
Run Code Online (Sandbox Code Playgroud)

模板:

<script>
    console.log( {{ data | tojson }} )
</script>
Run Code Online (Sandbox Code Playgroud)

渲染模板的输出:

<script>
    console.log( [1, 2, 3, 4] )
</script>
Run Code Online (Sandbox Code Playgroud)

可以safe添加,但也想{{ data | tojson | safe }}避免 html 转义,但它也可以在没有转义的情况下工作。