web-dev-qa-db-ja.com

Djangoテンプレート変数とJavascript

Djangoテンプレートレンダラーを使用してページをレンダリングするとき、さまざまな値を含む辞書変数を渡して、{{ myVar }}を使用してページ内で値を操作できます。

Javascriptで同じ変数にアクセスする方法はありますか(おそらくDOMを使用して、Djangoが変数にアクセスできるようにする方法がわかりません)。渡された変数に含まれる値に基づいてAJAXルックアップを使用して詳細をルックアップできるようにしたい。

180
AlMcLean

{{variable}}はHTMLに直接置き換えられます。ソースを表示します。 「変数」などではありません。テキストをレンダリングしただけです。

そうは言っても、この種の置換をJavaScriptに組み込むことができます。

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}";
</script>

これにより、「動的な」javascriptが得られます。

251
S.Lott

注意チケットの確認 #17419 Djangoコアおよび可能性のあるXSSへの同様のタグの追加についての議論ユーザーが生成したデータでこのテンプレートタグを使用することにより導入される脆弱性。 コメント amacneilから、チケットで発生したほとんどの懸念事項について説明します。


これを行う最も柔軟で便利な方法は、JSコードで使用する変数のテンプレートフィルターを定義することだと思います。これにより、データが適切にエスケープされ、dictlistなどの複雑なデータ構造で使用できるようになります。多くの賛成票で受け入れられた答えがあるにもかかわらず、私はこの答えを書くのです。

テンプレートフィルターの例を次に示します。

// myapp/templatetags/js.py

from Django.utils.safestring import mark_safe
from Django.template import Library

import json


register = Library()


@register.filter(is_safe=True)
def js(obj):
    return mark_safe(json.dumps(obj))

このテンプレートフィルタは、変数をJSON文字列に変換します。次のように使用できます。

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>
49
Yaroslav Admin

私のために働いた解決策は、テンプレートの非表示の入力フィールドを使用することです

<input type="hidden" id="myVar" name="variable" value="{{ variable }}">

次に、この方法でjavascriptの値を取得し、

var myVar = document.getElementById("myVar").value;
42
bosco-

Djangoによって変数が返されると、すべての引用符が&quot;に変換されます。 {{someDjangoVariable|safe}}を使用すると、Javascriptエラーが発生します。

これを修正するには、Javascript .replaceを使用します。

<script type="text/javascript"> 
    var json = "{{someDjangoVariable}}".replace(/&quot;/g,"\"")
</script>
9
Jon Sakas

辞書の場合、最初にJSONにエンコードするのが最適です。 simplejson.dumps()を使用できます。AppEngineのデータモデルから変換する場合は、GQLEncoderライブラリのencode()を使用できます。

8
jamtoday

Django 2.1の時点で、この使用例専用の組み込みテンプレートタグjson_scriptが導入されました。

https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#json-script

新しいタグはテンプレート値を安全にシリアル化し、XSSから保護します。

7
Jon Sakas

これは私が非常に簡単にやっていることです。テンプレート用にbase.htmlファイルを修正し、それを一番下に置きました:

{% if DJdata %}
    <script type="text/javascript">
        (function () {window.DJdata = {{DJdata|safe}};})();
    </script>
{% endif %}

次に、javascriptファイルで変数を使用する場合、DJdata辞書を作成し、jsonによってコンテキストに追加します:context['DJdata'] = json.dumps(DJdata)

それが役に立てば幸い!

6
Alexis Parakian

私は似たような問題に直面していましたが、S.Lottによって提案された答えは私のために働きました。

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}"
</script>

ただし、ここでは主要な実装上の制限を指摘したいと思います。 JavaScriptコードを別のファイルに入れて、そのファイルをテンプレートに含めることを計画している場合。これは機能しません。

これは、メインテンプレートとjavascriptコードが同じファイルにある場合にのみ機能します。おそらくDjangoチームはこの制限に対処できます。

3
Conquistador

私もこれに苦労しています。表面的には、上記のソリューションが機能するはずです。ただし、Djangoアーキテクチャでは、各htmlファイルに独自のレンダリング変数が必要です(つまり、{{contact}}contact.htmlにレンダリングされ、{{posts}}index.htmlなどになります)。一方、<script>タグは、{%endblock%}base.htmlが継承するcontact.htmlindex.htmlの後に表示されます。これは基本的に、

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

変数とスクリプトが同じファイルに共存できないため、失敗することになります。

最終的に思いついた、そして私のために働いた簡単な解決策は、変数をidのタグで単純にラップし、後でjsファイルでそれを参照することでした:

// index.html
<div id="myvar">{{ myVar }}</div>

その後:

// somecode.js
var someVar = document.getElementById("myvar").innerHTML;

通常どおり<script src="static/js/somecode.js"></script>base.htmlを含めます。もちろん、これはgettingコンテンツのみです。セキュリティに関しては、他の回答に従ってください。

3
Shoval Sadde

Djangoフィールドにテキストとして保存されたJavaScriptオブジェクトの場合、再びページ上のスクリプトに動的に挿入されるJavaScriptオブジェクトになる必要があるため、escapejsJSON.parse()の両方を使用する必要があります。

var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");

Djangoのescapejsはクォートを適切に処理し、JSON.parse()は文字列をJSオブジェクトに変換します。

1
shacker

変数を外部.jsスクリプトに渡す場合は、スクリプトタグの前に、グローバル変数を宣言する別のスクリプトタグを付ける必要があることに注意してください。

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>

dataは、通常、get_context_dataのビューで定義されます

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context
0
Daniel Kislyuk

次のように、配列変数が文字列で宣言されているスクリプト全体をアセンブルできます。

views.py

    aaa = [41, 56, 25, 48, 72, 34, 12]
    prueba = "<script>var data2 =["
    for a in aaa:
        aa = str(a)
        prueba = prueba + "'" + aa + "',"
    prueba = prueba + "];</script>"

次のように文字列を生成します

prueba = "<script>var data2 =['41','56','25','48','72','34','12'];</script>"

この文字列を取得した後、テンプレートに送信する必要があります

views.py

return render(request, 'example.html', {"prueba": prueba})

テンプレートでそれを受け取り、それを文学的な方法でhtmコードとして解釈します。たとえば、必要なjavascriptコードの直前に

テンプレート

{{ prueba|safe  }}

そしてその下はコードの残りの部分です。この例で使用する変数はdata2であることに注意してください

<script>
 console.log(data2);
</script>

そのようにして、データのタイプを保持します。この場合、これは配置です

0
Daniel Muñoz