Python変数があるとします:
_list_of_items = ['1','2','3','4','5']
_
hTMLをレンダリングしてJinjaに渡します。また、somefunction(variable)
というJavaScriptの関数もあります。 _list_of_items
_の各項目を渡そうとしています。私はこのようなものを試しました:
_{% for item in list_of_items %}
<span onclick="somefunction({{item}})">{{item}}</span><br>
{% endfor %}
_
リストをPythonからJavaScriptに渡すことはできますか、またはリスト内の各項目をループで1つずつ渡す必要がありますか?これを行うにはどうすればよいですか?
一部のコンテキストデータをjavascriptコードに渡すには、javascript(つまりJSON)によって「理解」されるようにシリアル化する必要があります。また、データがhtmlescapedされないように、safe
Jinjaフィルターを使用して安全とマークする必要があります。
これを実現するには、次のようなことを行います。
import json
@app.route('/')
def my_view():
data = [1, 'foo']
return render_template('index.html', data=json.dumps(data))
<script type="text/javascript">
function test_func(data) {
console.log(data);
}
test_func({{ data|safe }})
</script>
したがって、必要なものを正確に実現するには(アイテムのリストをループし、JavaScript関数に渡す)、リスト内のすべてのアイテムを個別にシリアル化する必要があります。コードは次のようになります。
import json
@app.route('/')
def my_view():
data = [1, "foo"]
return render_template('index.html', data=map(json.dumps, data))
{% for item in data %}
<span onclick=someFunction({{ item|safe }});>{{ item }}</span>
{% endfor %}
私の例では、Flask
を使用しています。どのフレームワークを使用しているかわかりませんが、アイデアはわかっています。使用するフレームワークに合わせて作成する必要があります。
ユーザー提供のデータでは絶対にこれを行わないでください。信頼できるデータでのみこれを行ってください!
そうでなければ、アプリケーションをXSSの脆弱性にさらすことになります!
Flaskを使用して同様の問題が発生しましたが、JSONに頼る必要はありませんでした。 render_template('show_entries.html', letters=letters)
を含むリスト_letters = ['a','b','c']
_を渡し、設定しました
_var letters = {{ letters|safe }}
_
私のjavascriptコードで。 Jinja2は_{{ letters }}
_を_['a','b','c']
_に置き換えました。これはjavascriptが文字列の配列として解釈したものです。
これを行うには、Jinjaの tojson
フィルターを使用します。
構造をJSONにダンプして、二重引用符で囲まれた属性の顕著な例外を除き、HTMLの任意の場所で
<script>
タグ[および]で安全に使用できるようにします。
たとえば、Pythonで次のように記述します。
some_template.render(list_of_items=list_of_items)
...または、Flaskエンドポイントのコンテキストで:
return render_template('your_template.html', list_of_items=list_of_items)
次に、テンプレートに次のように記述します。
{% for item in list_of_items %}
<span onclick='somefunction({{item | tojson}})'>{{item}}</span><br>
{% endfor %}
(onclick
属性はsingle-quotedであることに注意してください。|tojson
は'
文字をエスケープするため、これが必要です。ただし、出力には"
文字は含まれません。つまり、単一引用符で囲まれたHTML属性では安全に使用できますが、二重引用符で囲まれた属性では使用できません。
または、HTML属性の代わりにインラインスクリプトでlist_of_items
を使用するには、次のように記述します。
<script>
const jsArrayOfItems = {{list_of_items | tojson}};
// ... do something with jsArrayOfItems in JavaScript ...
</script>
PythonコードでJSONエンコード変数にjson.dumps
を使用して、結果のJSONテキストをテンプレートに渡すことはできません。これにより、一部の文字列値に対して誤った出力が生成され、これは、Pythonの組み込みjson.dumps
が<
や>
(安全にエスケープする必要がある)などの文字をエスケープしないためです。 https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements )に記載されているように、テンプレート値をインライン<script>
sに入れますまたは、単一引用符(安全に値を単一引用符で囲まれたHTML属性にテンプレート化するにはエスケープする必要があります)。
Flaskを使用している場合、FlaskはJinjaのバージョンを使用する代わりに、カスタム tojson
フィルターを挿入します。ただし、上記のすべてが適用されます。 2つのバージョンはほぼ同じように動作します; Flaskの単なる アプリ固有の設定が可能 これはJinjaのバージョンでは利用できません。
選択した答えを合計するために、jinja2とflaskを使用して動作する新しいオプションをテストしています:
@app.route('/')
def my_view():
data = [1, 2, 3, 4, 5]
return render_template('index.html', data=data)
テンプレート:
<script>
console.log( {{ data | tojson }} )
</script>
レンダリングされたテンプレートの出力:
<script>
console.log( [1, 2, 3, 4] )
</script>
safe
を追加することもできますが、{{ data | tojson | safe }}
しかし、それはあまりにも機能しています。
プロジェクトでjavascriptファイルを簡単に操作できるようにするjavascript指向のアプローチを提案できます。
Jinjaテンプレートファイルでjavascriptセクションを作成し、使用するすべての変数をjavascriptファイルでウィンドウオブジェクトに配置します。
Start.html
...
{% block scripts %}
<script type="text/javascript">
window.appConfig = {
debug: {% if env == 'development' %}true{% else %}false{% endif %},
facebook_app_id: {{ facebook_app_id }},
accountkit_api_version: '{{ accountkit_api_version }}',
csrf_token: '{{ csrf_token }}'
}
</script>
<script type="text/javascript" src="{{ url_for('static', filename='app.js') }}"></script>
{% endblock %}
Jinjaは値を置換し、appConfigオブジェクトは他のスクリプトファイルから到達可能になります。
App.js
var AccountKit_OnInteractive = function(){
AccountKit.init({
appId: appConfig.facebook_app_id,
debug: appConfig.debug,
state: appConfig.csrf_token,
version: appConfig.accountkit_api_version
})
}
管理しやすくseoに優しいこの方法で、htmlドキュメントからjavascriptコードを分離しました。