web-dev-qa-db-fra.com

Comment puis-je transmettre des données de Flask à JavaScript dans un modèle?

Mon application appelle une API qui renvoie un dictionnaire. Je souhaite transmettre les informations de ce dict à JavaScript dans la vue. J'utilise spécifiquement l'API Google Maps dans le JS. J'aimerais donc lui transmettre une liste de n-uplets avec les informations long/lat. Je sais que render_template transmettra ces variables à la vue afin qu'elles puissent être utilisées en HTML, mais comment puis-je les transmettre à JavaScript dans le modèle?

from flask import Flask
from flask import render_template

app = Flask(__name__)

import foo_api

api = foo_api.API('API KEY')

@app.route('/')
def get_data():
    events = api.call(get_event, arg0, arg1)
    geocode = event['latitude'], event['longitude']
    return render_template('get_data.html', geocode=geocode)
98
mea

Vous pouvez utiliser {{ variable }} n'importe où dans votre modèle, pas seulement dans la partie HTML. Donc, cela devrait fonctionner:

<html>
<head>
  <script>
    var someJavaScriptVar = '{{ geocode[1] }}';
  </script>
</head>
<body>
  <p>Hello World</p>
  <button onclick="alert('Geocode: {{ geocode[0] }} ' + someJavaScriptVar)" />
</body>
</html>

Considérez-le comme un processus en deux étapes: Premièrement, Jinja (le moteur de gabarit utilisé par Flask utilise) génère votre sortie texte. Ceci est envoyé à l'utilisateur qui exécute le JavaScript qu'il voit. Si vous voulez que votre variable Flask soit disponible en JavaScript sous forme de tableau, vous devez générer une définition de tableau dans votre sortie:

<html>
  <head>
    <script>
      var myGeocode = ['{{ geocode[0] }}', '{{ geocode[1] }}'];
    </script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
  </body>
</html>

Jinja propose également des constructions plus avancées à partir de Python, vous pouvez donc la raccourcir pour:

<html>
<head>
  <script>
    var myGeocode = [{{ ', '.join(geocode) }}];
  </script>
</head>
<body>
  <p>Hello World</p>
  <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>

Vous pouvez également utiliser les boucles for, les instructions if et bien d’autres, consultez le documentation de Jinja2 pour plus d’informations.

Regardez également la réponse de Ford qui indique le filtre tojson qui est un ajout à le jeu de filtres standard de Jinja2 .

Éditer novembre 2018: tojson est maintenant inclus dans l'ensemble de filtres standard de Jinja2.

117
mensi

Le moyen idéal pour obtenir à peu près n'importe quel objet Python dans un objet JavaScript est d'utiliser JSON. JSON est un excellent format pour le transfert entre systèmes, mais nous oublions parfois qu'il est synonyme de JavaScript Object Notation. Cela signifie qu'injecter du JSON dans le modèle équivaut à injecter du code JavaScript décrivant l'objet.

Flask fournit un filtre Jinja pour cela: tojson ajoute la structure à une chaîne JSON et la marque comme étant sûre pour que Jinja ne la copie pas automatiquement.

<html>
  <head>
    <script>
      var myGeocode = {{ geocode|tojson }};
    </script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
  </body>
</html>

Cela fonctionne pour toute structure Python JDS sérialisable:

python_data = {
    'some_list': [4, 5, 6],
    'nested_dict': {'foo': 7, 'bar': 'a string'}
}
var data = {{ python_data|tojson }};
alert('Data: ' + data.some_list[1] + ' ' + data.nested_dict.foo + 
      ' ' + data.nested_dict.bar);
94
ford

L'utilisation de attribut de données sur un élément HTML évite d'avoir à utiliser des scripts en ligne, ce qui signifie que vous pouvez utiliser règles CSP plus strictes pour une sécurité accrue.

Spécifiez un attribut de données comme suit:

<div id="mydiv" data-geocode='{{ geocode|tojson }}'>...</div>

Ensuite, accédez-y dans un fichier JavaScript statique comme ceci:

// Raw JavaScript
var geocode = JSON.parse(document.getElementById("mydiv").dataset.geocode);

// jQuery
var geocode = JSON.parse($("#mydiv").data("geocode"));
17
mcote

Vous pouvez également ajouter un noeud final pour renvoyer votre variable:

@app.route("/api/geocode")
def geo_code():
    return jsonify(geocode)

Ensuite, faites un XHR pour le récupérer:

fetch('/api/geocode')
  .then((res)=>{ console.log(res) })
7
Vinnie James

Des réponses de travail sont déjà fournies, mais je souhaite ajouter une vérification qui joue le rôle de sécurité intrinsèque au cas où la variable flask ne serait pas disponible. Quand vous utilisez:

var myVariable = {{ flaskvar | tojson }};

s'il existe une erreur qui rend la variable inexistante, les erreurs résultantes peuvent produire des résultats inattendus. Pour éviter cela:

{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}
3
Patrick Mutuku
<script>
    const geocodeArr = JSON.parse('{{ geocode | tojson }}');
    console.log(geocodeArr);
</script>

Ceci utilise jinja2 pour transformer le géocodage Tuple en une chaîne json, puis javascript JSON.parse le transforme en un tableau javascript.

2
nackjicholson

Juste une autre solution alternative pour ceux qui veulent passer des variables à un script qui est obtenu à l'aide de flask, je n'ai réussi à le faire fonctionner qu'en définissant les variables à l'extérieur, puis en appelant le script comme suit:

    <script>
    var myfileuri = "/static/my_csv.csv"
    var mytableid = 'mytable';
    </script>
    <script type="text/javascript" src="/static/test123.js"></script>

Si je saisis des variables jinja dans test123.js cela ne fonctionnera pas et vous obtiendrez une erreur.

2
tsando