Returning JSON array from a Django view to a template

后端 未结 3 858
野趣味
野趣味 2020-11-30 09:42

I\'m using Django to create a web-based app for a project, and I\'m running into issues returning an array from a Django view to a template.

The array will be used b

相关标签:
3条回答
  • 2020-11-30 10:08

    Edit with update for Django 2.1+ and the modern web:

    The modern way to do this is:

    1) Pass the raw data to the template, not the JSON-serialised data. I.e.:

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

    2) In your template, use the new "json_script" filter to include the JSON data:

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

    That will result in HTML that looks like this:

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

    This tag has special handling of strings containing "</script>" to make sure they work.

    3) In your Javascript code, get that tags data like this:

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

    4) Move your Javascript code to an external .js file, and set up the Content-Security-Policy header to prohibit inline Javascript because it's a security risk. Note that since the json_script tag generates JSON, not Javascript, it's safe and is allowed regardless of your Content-Security-Policy setting.

    Original Answer:

    WARNING: If any of the strings are user-controlled, this is insecure

    JSON is Javascript source code. I.e. the JSON representation of an array is the Javascript source code you need to define the array.

    So after:

    var tagbs = {{ tags|safe }};
    

    tagbs is a JavaScript array containing the data you want. There's no need to call JSON.parse(), because the web browser already parsed it as JavaScript source code.

    So you should be able to do

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

    and that should show "4".

    WARNING: With this old method, strings containing "</script>" will not work, they will go horribly wrong. This is because the browser will treat </script> as the end of the script. If any of the strings are user-entered data, this is an exploitable security flaw - see comment 14 here for more details. Use the more modern method above, instead.

    0 讨论(0)
  • 2020-11-30 10:08

    You want to JSON-ify the data in the template; JSON is already Javascript really (it's a subset:

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

    Note that tags is already JSON (thus JavaScript) data and can be inserted directly; no need to escape (there is no HTML here, it's JavaScript instead).

    Or you could use this Django snippet and do it straight in the template (no need to call serializers.serialize in the annotate method):

    var tgs = {{ tags|jsonify }};
    
    0 讨论(0)
  • 2020-11-30 10:30

    You can also use simplejson from django.utils. Like:

    oldAnnotations = lastFrame.videoannotation_set.filter(ParentVideoLabel=label)
    dump = simplejson.dumps(oldAnnotations)
    
    return HttpResponse(dump, mimetype='application/json')
    

    You can parse and reach all data in this from JS side.

    0 讨论(0)
提交回复
热议问题