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

时间:2012-06-24 14:50:40

标签: javascript python flask jinja2

我的应用程序调用返回字典的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)

9 个答案:

答案 0 :(得分:110)

您可以在模板中的任何位置使用{{ 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> 。所以这应该有效:

<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(Flask使用的模板引擎)生成文本输出。这会被发送给执行他看到的JavaScript的用户。如果您希望Flask变量在JavaScript中作为数组使用,则必须在输出中生成数组定义:

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

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

for

您还可以使用if循环,tojson语句等等,有关详情,请参阅Jinja2 documentation

另外,请看福特的答案,他们指出tojson过滤器是Jinja2's standard set of filters的补充。

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

答案 1 :(得分:90)

将任何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);

答案 2 :(得分:14)

在HTML元素上使用data attribute可以避免使用内联脚本,这反过来意味着您可以使用stricter CSP rules来提高安全性。

指定数据属性,如下所示:

<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"));

答案 3 :(得分:7)

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

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

然后做一个XHR来检索它:

fetch('/api/geocode')
  .then((res)=>{ console.log(res) })

答案 4 :(得分:3)

已经给出了有效的答案,但是我想添加一个检查,以在烧瓶变量不可用的情况下充当故障保险。 使用时:

var myVariable = {{ flaskvar | tojson }};

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

{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}

答案 5 :(得分:2)

对于那些想要将变量传递给使用flask来源的脚本的人来说,只是另一种替代解决方案,我只是通过在外部定义变量然后按如下方式调用脚本来设法实现这一点:

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

如果我在test123.js中输入jinja变量,它就不起作用,你会收到错误。

答案 6 :(得分:2)

<script>
    const geocodeArr = JSON.parse('{{ geocode | tojson }}');
    console.log(geocodeArr);
</script>

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

答案 7 :(得分:0)

嗯,对于这项工作,我有一个棘手的方法。这个想法如下-

在HTML主体中制作一些不可见的HTML标记,例如<label>, <p>, <input>等,并在标记ID中建立模式,例如,在标记ID中使用列表索引,在标记类名称处使用列表值。

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

{% 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>

答案 8 :(得分:-1)

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

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

This method使js文件保持不变(保持独立性),并正确传递变量!