web-dev-qa-db-ja.com

DjangoビューからテンプレートへのJSON配列を返す

Django=を使用してプロジェクト用のWebベースのアプリを作成しています。また、Djangoビューからテンプレート。

この配列は、ページに表示される画像にボックスを描画するためのJavaScript(JQuery)スクリプトによって使用されます。したがって、この配列には、とりわけ、描画されるボックスの座標が含まれます。

これは、必要なデータを取得してJSONとしてシリアル化するために使用されるDjangoビューのコードです:

_def annotate(request, ...):
    ...
    oldAnnotations = lastFrame.videoannotation_set.filter(ParentVideoLabel=label)
    tags = serializers.serialize("json", oldAnnotations)
    ...
    return render_to_response('vannotate.html', {'tags': tags, ...})
_

デバッグの方法として、テンプレートのHTML部分で_{{ tags }}_を使用すると、出力としてこれが得られます(長い行は申し訳ありません)。

_[{"pk": 491, "model": "va.videoannotation", "fields": {"ParentVideoFile": 4, "ParentVideoFrame": 201, "ParentVideoLabel": 4, "top": 220, "height": 30, "width": 30, "ParentVideoSequence": 16, "left": 242}}, {"pk": 492, "model": "va.videoannotation", "fields": {"ParentVideoFile": 4, "ParentVideoFrame": 201, "ParentVideoLabel": 4, "top": 218, "height": 30, "width": 30, "ParentVideoSequence": 16, "left": 307}}]
_

jSON配列の正しい形式だと思います。

後でテンプレートで、次のようにテンプレートのJavaScript部分でtags変数を実際に使用しようとします。

_{% if tags %}
  var tagbs = {{ tags|safe }};
  var tgs = JSON.parse(tagbs);
  alert("done");
{% endif %}
_

var tgs = JSON.parse(tagbs);行を削除すると、アラートボックスが正常にポップアップ表示され、残りのJavaScriptは期待どおりに機能します。ただし、この行をそのままにしておくと、スクリプトが中断されます。

Djangoモデルのすべてのオブジェクトを反復処理し、JavaScriptでフィールドの値を取得できるようにしたいと思います。

ここで何が間違っているのか分かりませんが、誰かがこれを行う正しい方法を指摘できますか?

25
DefPlayr

Django 2.1+および最新のWeb:の更新で編集

これを行う最新の方法は次のとおりです。

1)生データをJSONシリアル化されたデータではなくテンプレートに渡します。つまり:

def annotate(request, ...):
    ...
    oldAnnotations = lastFrame.videoannotation_set.filter(ParentVideoLabel=label)
    ...
    return render_to_response('vannotate.html', {'tags': oldAnnotations, ...})

2)テンプレートで、新しい「json_script」フィルターを使用してJSONデータを含めます。

{{ tags|json_script:"tags-data" }}

その結果、HTMLは次のようになります。

<script id="tags-data" type="application/json">{"foo": "bar"}</script>

このタグには、「</ script>」を含む文字列を特別に処理して、機能するようにします。

3)Javascriptコードで、次のようなタグデータを取得します。

var tags = JSON.parse(document.getElementById('tags-data').textContent);

4)Javascriptコードを外部.jsファイルに移動し、Content-Security-Policyヘッダーを設定して、インラインJavascriptを禁止します。これはセキュリティ上のリスクがあるためです。 json_scriptタグはJavascriptではなくJSONを生成するため、安全であり、Content-Security-Policy設定に関係なく許可されます。

元の答え:

警告:文字列のいずれかがユーザー制御の場合、これは安全ではありません

JSONisJavaScriptのソースコード。つまり配列のJSON表現は、配列を定義するために必要なJavascriptソースコードです。

だから後:

var tagbs = {{ tags|safe }};

tagbsは、必要なデータを含むJavaScript配列です。 JSON.parse()を呼び出す必要はありません。これは、WebブラウザーがすでにJavaScriptソースコードとして解析しているためです。

だからあなたはできるはずです

var tagbs = {{ tags|safe }};
alert(tagbs[0].fields.ParentVideoFile);

「4」が表示されます。

警告:この古い方法では、「</ script>」を含む文字列は機能せず、ひどく間違ってしまいます。これは、ブラウザが</ script>をスクリプトの終わりとして扱うためです。文字列のいずれかがユーザー入力データである場合、これは悪用可能なセキュリティ上の欠陥です。 詳細についてはコメント14を参照 。代わりに、上記のより新しい方法を使用してください

37
user9876

テンプレートのデータをJSON化したい; JSONはすでにJavascriptです(サブセットです:

{% if tags %}
  var tgs = {{ tags }};
{% endif %}

tagsはすでにJSON(つまりJavaScript)データであり、直接挿入できる;エスケープする必要はありません(ここにはHTMLはありません。代わりにJavaScriptです)。

または、この Djangoスニペット を使用して、テンプレートで直接実行することもできます(annotateメソッドでserializers.serializeを呼び出す必要はありません)。

var tgs = {{ tags|jsonify }};
4
Martijn Pieters

Django.utilsからsimplejsonを使用することもできます。お気に入り:

oldAnnotations = lastFrame.videoannotation_set.filter(ParentVideoLabel=label)
dump = simplejson.dumps(oldAnnotations)

return HttpResponse(dump, mimetype='application/json')

JS側からこの中のすべてのデータを解析して到達できます。

2
alix