如何在模板中将数据从 Flask 传递到 JavaScript?
- 2025-01-14 08:50:00
- admin 原创
- 104
问题描述:
我的应用程序调用一个返回字典的 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)
解决方案 1:
您可以{{ 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 文档。
另外,看一下福特的回答,他指出该过滤器是Jinja2 标准过滤器集的tojson
补充。
2018 年 11 月编辑:tojson
现已包含在 Jinja2 的标准过滤器集中。
解决方案 2:
将几乎任何 Python 对象转换为 JavaScript 对象的理想方法是使用 JSON。JSON 非常适合在系统之间传输,但有时我们会忘记它代表 JavaScript 对象表示法。这意味着将 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);
解决方案 3:
在 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"));
解决方案 4:
或者,您可以添加一个端点来返回您的变量:
@app.route("/api/geocode")
def geo_code():
return jsonify(geocode)
然后执行 XHR 来检索它:
fetch('/api/geocode')
.then((res)=>{ console.log(res) })
解决方案 5:
已经给出了可行的答案,但我想添加一个检查,以防 flask 变量不可用时起到故障保护的作用。当您使用时:
var myVariable = {{ flaskvar | tojson }};
如果存在导致变量不存在的错误,则导致的错误可能会产生意外结果。为了避免这种情况:
{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}
解决方案 6:
对于那些想要将变量传递给使用 flask 的脚本的人来说,这只是另一种替代解决方案,我只能通过在外部定义变量然后调用脚本来实现这一点,如下所示:
<script>
var myfileuri = "/static/my_csv.csv"
var mytableid = 'mytable';
</script>
<script type="text/javascript" src="/static/test123.js"></script>
如果我输入 jinja 变量,test123.js
它不起作用,并且您会收到错误。
解决方案 7:
<script>
const geocodeArr = JSON.parse('{{ geocode | tojson }}');
console.log(geocodeArr);
</script>
这使用 jinja2 将地理编码元组转换为 json 字符串,然后 javascriptJSON.parse
将其转换为 javascript 数组。
解决方案 8:
嗯,我有一个巧妙的方法来完成这项工作。思路如下:
在 HTML 主体中创建一些不可见的 HTML 标签,例如<label>, <p>, <input>
等,并在标签 id 中制定一个模式,例如,在标签 id 中使用列表索引,在标签类名中使用列表值。
这里我有两个长度相同的列表maintenance_next[]和maintenance_block_time[]。我想使用flask将这两个列表的数据传递给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%}
运行代码片段Hide results展开片段
此后,我使用一些简单的 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>
运行代码片段Hide results展开片段
解决方案 9:
有些 js 文件来自网络或者库,不是你自己写的。它们获取变量的代码如下:
var queryString = document.location.search.substring(1);
var params = PDFViewerApplication.parseQueryString(queryString);
var file = 'file' in params ? params.file : DEFAULT_URL;
此方法不改变js文件(保持独立性),且能正确传递变量!