如何在模板中将Flask中的数据传递给JavaScript?

mea*_*mea 105 javascript python jinja2 flask

我的应用程序调用返回字典的API.我想在视图中将此dict中的信息传递给JavaScript.我特意在JS中使用Google Maps API,所以我想传递一个带有long/lat信息的元组列表.我知道这render_template会将这些变量传递给视图,因此可以在HTML中使用它们,但是如何将它们传递给模板中的JavaScript?

from flask import Flask
from flask import render_template

app = Flask(__name__)

import foo_api

api = foo_api.API('API KEY')

@app.route('/')
def get_data():
    events = api.call(get_event, arg0, arg1)
    geocode = event['latitude'], event['longitude']
    return render_template('get_data.html', geocode=geocode)
Run Code Online (Sandbox Code Playgroud)

men*_*nsi 122

您可以{{ variable }}在模板中的任何位置使用,而不仅仅在HTML部分中使用.所以这应该工作:

<html>
<head>
  <script>
    var someJavaScriptVar = '{{ geocode[1] }}';
  </script>
</head>
<body>
  <p>Hello World</p>
  <button onclick="alert('Geocode: {{ geocode[0] }} ' + someJavaScriptVar)" />
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

可以将其视为一个两阶段过程:首先,Jinja(Flask使用的模板引擎)生成文本输出.这会被发送给执行他看到的JavaScript的用户.如果您希望Flask变量在JavaScript中作为数组使用,则必须在输出中生成数组定义:

<html>
  <head>
    <script>
      var myGeocode = ['{{ geocode[0] }}', '{{ geocode[1] }}'];
    </script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

Jinja还提供了Python的更高级构造,因此您可以将其缩短为:

<html>
<head>
  <script>
    var myGeocode = [{{ ', '.join(geocode) }}];
  </script>
</head>
<body>
  <p>Hello World</p>
  <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

您还可以使用for循环,if语句等等,有关详细信息,请参阅Jinja2文档.

另外,请看福特的答案,他们指出tojson过滤器是Jinja2标准过滤器的补充.

编辑2018年11月:tojson现在包含在Jinja2的标准过滤器中.

  • 非常感谢,mensi!这是我最初的想法,但 Flask 的文档并没有明确说明您也可以在 JS 中使用 {{var}} 形式。感谢您解决这个问题。 (2认同)
  • @mea:你也可以使用模板引擎生成任意基于文本的文件,我也用它来动态生成TeX文件( - > PDF)和电子邮件,它的用途非常广泛;) (2认同)
  • 这是有道理的,但是您发布的解决方案似乎需要我在 JS 数组的内容中手动编码。我希望我可以更编程地做到这一点,这样我就可以传递一个可变长度的 Python 列表,并且一个 JS for 循环可以遍历整个长度,然后将它们附加到 JS 数组中。对不起,如果我没有让自己足够清楚,但我对 JS 和 Web 开发人员相当友好。 (2认同)
  • @RocketPingu 如果你想在一个单独的文件中传递数据,通常只使用 `json` 模块以 json 对象的形式转储你的数据会更容易 (2认同)

for*_*ord 98

将任何Python对象变为JavaScript对象的理想方法是使用JSON.JSON非常适合作为系统之间传输的格式,但有时我们会忘记它代表JavaScript Object Notation.这意味着将JSON注入模板与注入描述对象的JavaScript代码相同.

Flask为此提供了一个Jinja过滤器:tojson将结构转储为JSON字符串并将其标记为安全,以便Jinja不会自动显示它.

<html>
  <head>
    <script>
      var myGeocode = {{ geocode|tojson }};
    </script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

这适用于任何JSON可序列化的Python结构:

python_data = {
    'some_list': [4, 5, 6],
    'nested_dict': {'foo': 7, 'bar': 'a string'}
}
Run Code Online (Sandbox Code Playgroud)
var data = {{ python_data|tojson }};
alert('Data: ' + data.some_list[1] + ' ' + data.nested_dict.foo + 
      ' ' + data.nested_dict.bar);
Run Code Online (Sandbox Code Playgroud)

  • 我发现这个答案比公认的答案更加坚实和合乎逻辑. (6认同)
  • 下次在javascript控制台中收到`Uncaught SyntaxError:Unexpected token&`时尝试这个. (3认同)

小智 18

在HTML元素上使用数据属性可以避免使用内联脚本,这反过来意味着您可以使用更严格的CSP规则来提高安全性.

像这样指定数据属性:

<div id="mydiv" data-geocode='{{ geocode|tojson }}'>...</div>
Run Code Online (Sandbox Code Playgroud)

然后在静态JavaScript文件中访问它,如下所示:

// Raw JavaScript
var geocode = JSON.parse(document.getElementById("mydiv").dataset.geocode);

// jQuery
var geocode = JSON.parse($("#mydiv").data("geocode"));
Run Code Online (Sandbox Code Playgroud)


Vin*_*mes 8

或者,您可以添加端点以返回变量:

@app.route("/api/geocode")
def geo_code():
    return jsonify(geocode)
Run Code Online (Sandbox Code Playgroud)

然后做一个XHR来检索它:

fetch('/api/geocode')
  .then((res)=>{ console.log(res) })
Run Code Online (Sandbox Code Playgroud)

  • 是的,您*可以*,并且在某些架构(尤其是 SPA)中,这是正确的处理方式,但请记住,与在提供数据时将数据烘焙到页面中相比,这样做有几个缺点:1 . 它速度较慢, 2. 即使是马虎地执行,它也需要稍微多一点的代码,并且 3. 它引入了至少两个额外的前端状态,您可能需要在 UI 中干净地处理这些状态(即 XHR 请求仍然处于状态)飞行中的,以及完全失败的),这需要一堆额外的 JavaScript 代码,并引入额外的潜在错误来源。 (3认同)

Pat*_*uku 7

已经给出了工作答案,但我想添加一个检查,在 Flask 变量不可用的情况下充当故障安全装置。当您使用:

var myVariable = {{ flaskvar | tojson }};
Run Code Online (Sandbox Code Playgroud)

如果存在导致变量不存在的错误,则由此产生的错误可能会产生意外的结果。为了避免这种情况:

{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}
Run Code Online (Sandbox Code Playgroud)