wake-up-neo.com

Objekte von Django an Javascript DOM übergeben

Ich versuche, ein Abfrageset von Django an eine Vorlage mit Javascript zu übergeben.

Ich habe verschiedene Ansätze ausprobiert, um das zu lösen:

1. Normaler Ansatz - Javascript wird aufgrund der Nomenklatur durch den Versuch, das Objekt zu analysieren, durcheinander gebracht [& gt Objekt: ID & lt, & gt Objekt: ID & lt, ...]

Django View

Django_list = list(Some_Object.objects.all())

Vorlage HTML + JS

<script type="text/javascript" >
    var js_list = {{Django_list}};
</script>

2. JSON-Ansatz - Django schlägt beim Konvertieren der Objektliste in eine Json-Zeichenfolge fehl Ist nicht in JSON serialisierbar.

Django View

Django_list = list(Some_Object.objects.all())
json_list = simplejson.dumps(Django_list)

Vorlage HTML + JS

<script type="text/javascript" >
    var js_list = {{json_list}};
</script>

Also brauche ich hier etwas Hilfe :)

Hat jemand einen Vorschlag/Lösung?

Vielen Dank!

30
Mc-

Ok, ich habe die Lösung gefunden!

Meistens lag es daran, die Ergebnisse nicht zu zitieren. Wenn Javascript das Objekt analysieren wollte, wurde dies nicht als Zeichenfolge erkannt.

Der erste Schritt ist also:

var js_list = {{Django_list}}; 

gewechselt zu:

var js_list = "{{Django_list}}";

Danach erkannte ich, dass Django Charakteren entkam, also musste ich sie wie folgt ersetzen:

 var myJSONList = (("{{json_list}}").replace(/&(l|g|quo)t;/g, function(a,b){
                return {
                    l   : '<',
                    g   : '>',
                    quo : '"'
                }[b];
            }));

 myData = JSON.parse( myJSONList );

Hinweis: Ich habe versucht zu vermeiden, Zeichen aus Django mit diesem zu umgehen :

var js_list = "{{json_list|safe}}"; 

Das funktioniert aber nicht, weil es mit den Zitaten verwechselt wird.

Schließlich habe ich einen Weg gefunden, die Logik im Backend der Konvertierung in JSON vor dem Senden an Javascript zu vermeiden: 

var myDjangoList = (("{{Django_list |safe}}").replace(/&(l|g|quo)t;/g, function(a,b){
            return {
                l   : '<',
                g   : '>',
                quo : '"'
            }[b];
        }));

myDjangoList = myDjangoList.replace(/u'/g, '\'')
myDjangoList = myDjangoList.replace(/'/g, '\"')

myData = JSON.parse( myDjangoList );

Ich bin mir sicher, dass dies verbessert werden kann, ich lasse es dir zu;)

Danke für deine Antworten

Hoffe es hilft jemand anderem!

24
Mc-

Gleiche Frage, "Besser" (neuere) Antwort: Django Queryset zur Verwendung in Json diktieren

Antwort von vashishtha-jogi :

Ein besserer Ansatz ist die Verwendung von DjangoJSONEncoder. Es hat Unterstützung für Decimal.

import json
from Django.core.serializers.json import DjangoJSONEncoder

prices = Price.objects.filter(product=product).values_list('price','valid_from')

prices_json = json.dumps(list(prices), cls=DjangoJSONEncoder)

Sehr einfach zu bedienen Kein Durchspringen der Reifen für die Konvertierung einzelner Felder zu schweben.

Update: Die Antwort wurde dahingehend geändert, dass der eingebaute Json anstelle von SimpleJson verwendet wird.

Diese Antwort wurde so oft bei meinen Google-Suchen gefunden und hat so viele Ansichten, dass es eine gute Idee zu sein scheint, sie zu aktualisieren und alle anderen vor dem Durchsuchen von SO zu bewahren. Nimmt Django 1.5 an.

29
agconti

Django-Abfragesätze sind serialisierbar durch JSON . Einige Feldtypen (wie anscheinend Datum) können bei nicht serialisiert werden. Eine Problemumgehung für Datumsobjekte finden Sie in eine weitere Frage zu JSON und Python .

Ich würde empfehlen, Wörterbücher direkt in JavaScript selbst zu erstellen. Gegebene Modelle wie dieses:

class Article(models.Model):
    title = models.CharField(max_length=100)
    slug = models.SlugField()
    content = models.TextField()

class Author(models.Model):
    article = models.ForeignKey("Article", related_name="authors")
    first_name=models.CharField(max_length=100)
    last_name=models.CharField(max_length=100)

Ich würde so etwas in der Vorlage machen:

<script type="text/javascript">
    var articles = [
    {% for article in article_list %}
        {% if not forloop.first %},{% endif %}
        {
            title: "{{ article.title }}",
            slug: "{{ article.slug }}",
            content: "{{ article.content }}",
            authors: [
            {% for author in article.authors.all %}
                {% if not forloop.first %},{% endif %}
                {
                    first_name: "{{ author.first_name }}",
                    last_name: "{{ author.last_name }}",
                }
            {% endfor %}
            ]
        }
    {% endfor %}
    ]
</script>

Wenn Sie die Frage vielleicht ein wenig schlecht formuliert haben und sind nicht planen, Code in ein <script> -Tag einzufügen und tatsächlich benötigen JSON aus irgendeinem Grund würde ich einfach eine Schleife in der Ansicht machen und eine Liste von dicts erstellen, bei denen JSON keine Probleme mit der Serialisierung hat, und JavaScript kein Problem beim Verstehen.

8
Jordan Reiter

BEARBEITEN: Bitte verwenden Sie diese Methode nicht, siehe @ agcontis Antwort.

Verwenden Sie den Escapejs-Filter: https://docs.djangoproject.com/de/1.4/ref/templates/builtins/#escapejs

Beispiel für das Ablegen einer Liste:

var foo = [{% for x in y %}'{{ x|escapejs }}',{% endfor %}]
7
boxed

Sie können die Kombination aus safe und escapejs eingebautem Filter in Django verwenden.

var json_string = unescape({{json_list | safe | escapejs}});
var json_data = JSON.parse(json_string);
6
lguiel

Ihr Problem ist, dass, wie so oft, Ihre Anforderungen zu niedrig sind. Wie genau soll der JSON aussehen? Sie sagen, Sie möchten das Queryset "serialisieren", aber in welchem ​​Format? Möchten Sie alle Felder von jeder Modellinstanz, eine Auswahl oder nur die Unicode-Darstellung? Wenn Sie diese Frage beantwortet haben, wissen Sie, wie Sie Ihr Problem lösen können.

Ein Ansatz könnte beispielsweise darin bestehen, die values queryset-Methode zu verwenden, um ein Wörterbuch mit Feldern für jede Instanz auszugeben und dieses zu serialisieren (Sie müssen es zuerst in eine Liste konvertieren):

data = SomeObject.objects.values('field1', 'field2', 'field3')
serialized_data = simplejson.dumps(list(data))
4
Daniel Roseman

Sie müssen die Zeichenfolge als sicher markieren, um sicherzustellen, dass sie nicht maskiert ist.

in einem meiner Projekte verwende ich es so:

# app/templatetag/jsonify.py
from Django import template
from Django.utils.safestring import mark_safe
import json

register = template.Library()

@register.filter
def jsonify(list):
    return mark_safe(json.dumps(list))

und in der Vorlage

{% load jsonify %}
<script type="text/javascript" >
    var js_list = {{ python_list|jsonify|escapejs }};
</script>

sie können jedoch lieber mark_safe hinzufügen oder | safe in der Vorlage verwenden, um alles &gt;-Zeug zu vermeiden

Wenn das Problem in der Handhabung komplexer Python-Objekte liegt, müssen Sie Ihren Handler möglicherweise wie folgt ausführen: JSON-Datumszeit zwischen Python und JavaScript

3
christophe31

Django bietet integrierte Hilfe für das Szenario, das Sie hier versuchen. Es geht ungefähr so:

Sie haben eine Python-Sequenz, eine Liste, ein Wörterbuch usw. in Ihrer Ansicht, nennen wir sie py_object. Ein Ansatz besteht darin, sie zu jsonifizieren, bevor sie an die Rendering-Engine übergeben werden.

from Django.shortcuts import render_to_response
import json  

Dann später so verwenden ...

render_to_response('mypage.html',{'js_object':json.dumps(py_object)})

Verwenden Sie dann in Ihrer Vorlage den safe-Filter, um das bereits jsonized-Objekt aus Python in Javascript zu importieren, wie hier ...

data = {{ js_object|safe }}

Das sollte dein Problem lösen, hoffe ich.

2
nemesisfixx

Seit Django 2.1 gibt es das json-script Template-Tag . Aus den Dokumenten:

json_script

Gibt ein Python-Objekt sicher als JSON aus, eingebettet in ein Tag bereit für die Verwendung mit JavaScript.

Argument: HTML-ID des Tags.

Zum Beispiel:

{{ value|json_script:"hello-data" }} 

Wenn value das Wörterbuch {'hello': 'world'} ist, wird folgende Ausgabe ausgegeben:

<script id="hello-data" type="application/json">
{"hello": "world"}
</script>

Auf die resultierenden Daten kann in JavaScript zugegriffen werden so was:

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

XSS-Angriffe werden durch das Umgehen der Zeichen „<“, „>“ und „&“ gemildert. Zum Beispiel: Wenn der Wert {'hello': 'world</script>&amp;'} ist, lautet die Ausgabe:

<script id="hello-data" type="application/json">
    {"hello": "world\\u003C/script\\u003E\\u0026amp;"}
</script> 

Dies ist kompatibel mit einer strengen Inhaltssicherheitsrichtlinie, die das In-Page-Skript verbietet Ausführung. Es hält auch eine saubere Trennung zwischen passiven Daten und ausführbarer Code.

0
LaundroMat

Konsolidierte Antwort (mein Env: Django 2.0)

In views.py

import json
data= []
// fil the list
context['mydata'] = json.dumps({'data':data})

In der Vorlage

  <script type="text/javascript">
      var mydataString = "{{mydata|escapejs}}";
      console.log(JSON.parse(mydataString));
  </script>
0
rogoro