wake-up-neo.com

Wie man eine Liste von Python durch Jinja2 an JavaScript übergibt

Nehmen wir an, ich habe eine Python-Variable:

list_of_items = ['1','2','3','4','5']

und ich übergebe es an Jinja, indem ich HTML rendere. Außerdem habe ich in JavaScript eine Funktion namens somefunction(variable). Ich versuche jedes Element von list_of_items zu übergeben. Ich habe so etwas ausprobiert:

{% for item in list_of_items %}
<span onclick="somefunction({{item}})">{{item}}</span><br>
{% endfor %}

Ist es möglich, eine Liste von Python an JavaScript zu übergeben, oder sollte ich jedes Element in einer Schleife nacheinander übergeben? Wie kann ich das machen?

52
user1843766

Um einige Kontextdaten an Javascript-Code zu übergeben, müssen Sie sie so serialisieren, dass sie von Javascript (nämlich JSON) "verstanden" werden. Sie müssen sie auch mit dem safe Jinja-Filter als sicher markieren, um zu verhindern, dass Ihre Daten htmlescaped werden.

Sie können dies erreichen, indem Sie Folgendes tun:

Die Aussicht

import json

@app.route('/')
def my_view():
    data = [1, 'foo']
    return render_template('index.html', data=json.dumps(data))

Die Vorlage

<script type="text/javascript">
    function test_func(data) {
        console.log(data);
    }
    test_func({{ data|safe }})
</script>

Bearbeiten - genaue Antwort

Um genau das zu erreichen, was Sie möchten (eine Liste von Elementen durchlaufen und an eine Javascript-Funktion übergeben), müssen Sie jeden Eintrag in Ihrer Liste separat serialisieren. Ihr Code würde dann so aussehen:

Die Aussicht

import json

@app.route('/')
def my_view():
    data = [1, "foo"]
    return render_template('index.html', data=map(json.dumps, data))

Die Vorlage

{% for item in data %}
    <span onclick=someFunction({{ item|safe }});>{{ item }}</span>
{% endfor %}

Bearbeiten 2

In meinem Beispiel verwende ich Flask. Ich weiß nicht, welches Framework Sie verwenden, aber Sie haben die Idee, Sie müssen es nur an das Framework anpassen, das Sie verwenden.

Edit 3 (Sicherheitswarnung)

NIEMALS DIESES MIT NUTZERDATEN, NUR MIT VERTRAUENSDATEN!

Andernfalls würden Sie Ihre Anwendung XSS-Schwachstellen aussetzen!

80
mdeous

Ich hatte ein ähnliches Problem mit Flask, musste aber nicht auf JSON zurückgreifen. Ich habe gerade eine Liste letters = ['a','b','c'] mit render_template('show_entries.html', letters=letters) übergeben und eingestellt 

var letters = {{ letters|safe }}

in meinem Javascript-Code. Jinja2 ersetzte {{ letters }} durch ['a','b','c'], das Javascript als Array von Strings interpretiert.

24
Godsmith

Um die ausgewählte Antwort zusammenzufassen, habe ich eine neue Option getestet, die auch mit jinja2 und flask funktioniert:

@app.route('/')
def my_view():
    data = [1, 2, 3, 4, 5]
    return render_template('index.html', data=data)

Die Vorlage:

<script>
    console.log( {{ data | tojson }} )
</script>

die Ausgabe der gerenderten Vorlage:

<script>
    console.log( [1, 2, 3, 4] )
</script>

Die safe könnte aber auch wie {{ data | tojson | safe }} hinzugefügt werden, funktioniert aber auch ohne.

0
Sylhare

Ich kann Ihnen einen an Javascript orientierten Ansatz vorschlagen, der es Ihnen leicht macht, mit Javascript-Dateien in Ihrem Projekt zu arbeiten.

Erstellen Sie einen Javascript-Abschnitt in Ihrer Jinja-Vorlagendatei und platzieren Sie alle Variablen, die Sie in Ihren Javascript-Dateien verwenden möchten, in einem Fensterobjekt:

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 ersetzt die Werte und unser appConfig-Objekt ist über unsere anderen Skriptdateien erreichbar:

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
    })
}

Ich habe Javascript-Code von HTML-Dokumenten auf diese Weise getrennt, die einfacher zu verwalten und seo-freundlich ist.

0
muratgozel

Sie können dies mit dem Filter { tojson von Jinja tun, der den

Gibt eine Struktur in JSON aus, sodass sie in <script>-Tags [und] an beliebiger Stelle in HTML verwendet werden kann, mit der bemerkenswerten Ausnahme von Attributen mit doppelten Anführungszeichen.

Schreiben Sie beispielsweise in Ihrem Python:

some_template.render(list_of_items=list_of_items)

... oder im Zusammenhang mit einem Flaschenendpunkt:

return render_template('your_template.html', list_of_items=list_of_items)

Dann schreibe in deine Vorlage:

{% for item in list_of_items %}
<span onclick='somefunction({{item | tojson}})'>{{item}}</span><br>
{% endfor %}

(Beachten Sie, dass das onclick-Attribut single -) ist. Dies ist erforderlich, da |tojson'-Zeichen, jedoch keine "-Zeichen in seiner Ausgabe entweicht. Dies bedeutet, dass es in einfach zitierten HTML-Attributen sicher verwendet werden kann, jedoch nicht in doppelten Anführungszeichen .)

Um list_of_items in einem Inline-Skript anstelle eines HTML-Attributs zu verwenden, geben Sie Folgendes ein:

<script>
const jsArrayOfItems = {{list_of_items | tojson}};
// ... do something with jsArrayOfItems in JavaScript ...
</script>

Verwenden Sie NICHT json.dumps für JSON-encode-Variablen in Ihrem Python-Code und übergeben Sie den resultierenden JSON-Text an Ihre Vorlage. Dies erzeugt eine falsche Ausgabe für einige Zeichenfolgewerte und macht Sie für XSS verfügbar, wenn Sie versuchen, die vom Benutzer angegebenen Werte zu kodieren. Dies ist darauf zurückzuführen, dass in Pythons json.dumps Zeichen wie < und > (die zur sicheren Vorlage von Werten in Inline-<script>s geschützt werden müssen) nicht maskiert werden, wie unter https://html.spec.whatwg.org/multipage/scripting angegeben .html # Einschränkungen-for-Contents-of-script-elements ) oder einfache Anführungszeichen (für die eine sichere Vorlage von Werten in HTML-Attributen mit einfachen Anführungszeichen erforderlich ist).

Wenn Sie Flask verwenden, beachten Sie, dass Flask einen benutzerdefinierten tojson - Filter injiziert, anstatt die Version von Jinja zu verwenden. Alles, was oben geschrieben wurde, gilt jedoch weiterhin. Die beiden Versionen verhalten sich fast identisch. Flask ist nur erlaubt eine App-spezifische Konfiguration , das in Jinjas Version nicht verfügbar ist.

0
Mark Amery