151

我的应用程序调用返回字典的 API。我想将此字典中的信息传递给视图中的 JavaScript。具体来说,我在 JS 中使用 Google Maps API,所以我想向它传递一个包含长/纬度信息的元组列表。我知道这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)
4

10 回答 10

176

您可以{{ 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>

把它想象成一个两阶段的过程:首先,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>

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>

您还可以使用for循环、if语句等,更多信息请参见Jinja2 文档

另外,请查看 Ford 的回答,他指出tojson过滤器是Jinja2 标准过滤器集的补充。

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

于 2012-06-24T14:59:00.967 回答
130

将几乎所有 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>

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

python_data = {
    'some_list': [4, 5, 6],
    'nested_dict': {'foo': 7, 'bar': 'a string'}
}
var data = {{ python_data|tojson }};
alert('Data: ' + data.some_list[1] + ' ' + data.nested_dict.foo + 
      ' ' + data.nested_dict.bar);
于 2014-04-14T21:58:01.140 回答
35

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

像这样指定数据属性:

<div id="mydiv" data-geocode='{{ geocode|tojson }}'>...</div>

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

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

// jQuery
var geocode = JSON.parse($("#mydiv").data("geocode"));
于 2017-06-30T07:17:51.370 回答
12

或者,您可以添加一个端点来返回您的变量:

@app.route("/api/geocode")
def geo_code():
    return jsonify(geocode)

然后做一个 XHR 来检索它:

fetch('/api/geocode')
  .then((res)=>{ console.log(res) })
于 2017-05-15T18:21:54.707 回答
5

工作答案已经给出,但我想添加一个检查,以防烧瓶变量不可用。当您使用:

var myVariable = {{ flaskvar | tojson }};

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

{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}
于 2018-07-04T17:30:01.967 回答
4

对于那些想要将变量传递给使用烧瓶获取的脚本的人来说,这只是另一种替代解决方案,我只能通过在外部定义变量然后调用脚本来使其工作,如下所示:

    <script>
    var myfileuri = "/static/my_csv.csv"
    var mytableid = 'mytable';
    </script>
    <script type="text/javascript" src="/static/test123.js"></script>

如果我在其中输入 jinja 变量test123.js不起作用,您将收到错误消息。

于 2017-02-10T11:34:45.013 回答
3
<script>
    const geocodeArr = JSON.parse('{{ geocode | tojson }}');
    console.log(geocodeArr);
</script>

这使用 jinja2 将地理编码元组转换为 json 字符串,然后 javascriptJSON.parse将其转换为 javascript 数组。

于 2018-12-29T19:05:35.710 回答
1

好吧,我有一个棘手的方法来完成这项工作。思路如下——

在 HTML body 中制作一些不可见的 HTML 标签,如<label>, <p>, <input>etc.,并在标签 id 中制作模式,例如,在标签 id 中使用列表索引,在标签类名称中使用列表值。

在这里,我有两个相同长度的列表 maintenance_next[] 和 maintenance_block_time[]。我想使用烧瓶将这两个列表的数据传递给 javascript。所以我取了一些不可见的标签标签并将其标签名称设置为列表索引的模式并将其类名设置为索引处的值。

{% for i in range(maintenance_next|length): %}
<label id="maintenance_next_{{i}}" name="{{maintenance_next[i]}}" style="display: none;"></label>
<label id="maintenance_block_time_{{i}}" name="{{maintenance_block_time[i]}}" style="display: none;"></label>
{% endfor%}

在此之后,我使用一些简单的 javascript 操作在 javascript 中检索数据。

<script>
var total_len = {{ total_len }};

for (var i = 0; i < total_len; i++) {
    var tm1 = document.getElementById("maintenance_next_" + i).getAttribute("name");
    var tm2 = document.getElementById("maintenance_block_time_" + i).getAttribute("name");
    
    //Do what you need to do with tm1 and tm2.
    
    console.log(tm1);
    console.log(tm2);
}
</script>

于 2019-12-09T05:13:39.437 回答
0

真棒线程!这有很大帮助!这是我完成的伪代码:

我的页面.html

<script>
    var user = {{username}}
</script>

我的页面.js

console.log('username = ' + user)
于 2022-01-26T16:41:33.157 回答
-1

有些js文件来自网络或者库,不是自己写的。他们得到变量的代码如下:

var queryString = document.location.search.substring(1);
var params = PDFViewerApplication.parseQueryString(queryString);
var file = 'file' in params ? params.file : DEFAULT_URL;

此方法使js文件不变(保持独立),并正确传递变量!

于 2017-11-22T04:28:56.370 回答