web-dev-qa-db-ja.com

テンプレートでFlaskからJavaScriptにデータを渡すにはどうすればよいですか?

私のアプリは辞書を返すAPIを呼び出します。この辞書の情報をビューの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)
98
mea

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

2段階のプロセスと考えてください。まず、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 フィルターを指摘しているFordの回答もご覧ください。

2018年11月編集:tojsonがJinja2の標準フィルターセットに含まれるようになりました。

117
mensi

ほぼすべての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);
94
ford

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

または、エンドポイントを追加して変数を返すこともできます。

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

次に、XHRを実行して取得します。

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

実用的な答えはすでに与えられていますが、flask変数が利用できない場合にフェールセーフとして機能するチェックを追加したいと思います。使用する場合:

var myVariable = {{ flaskvar | tojson }};

変数が存在しない原因となるエラーがある場合、結果のエラーにより予期しない結果が生じる可能性があります。これを回避するには:

{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}
3
Patrick Mutuku
<script>
    const geocodeArr = JSON.parse('{{ geocode | tojson }}');
    console.log(geocodeArr);
</script>

これは、jinja2を使用してジオコードタプルをjson文字列に変換し、javascript JSON.parseがそれをjavascript配列に変換します。

2
nackjicholson

フラスコを使用してソースされたスクリプトに変数を渡したい人のための別の代替ソリューションは、変数を外部で定義し、次のようにスクリプトを呼び出すことでこれを動作させることができました:

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

test123.jsにjinja変数を入力すると機能せず、エラーが発生します。

2
tsando