python - Hur kan jag skicka data från Flask till JavaScript i en mall?
Min app gör ett anrop till ett API som returnerar en ordlista. Jag vill skicka information från denna ordlista till JavaScript i vyn. Jag använder Google Maps API i JS specifikt, så jag skulle vilja skicka en lista med tupler med longitud-/latitudinformation. Jag vet att render_template kommer att skicka dessa variabler till vyn så att de kan användas i HTML, men hur skulle jag kunna skicka dem till JavaScript i mallen?
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)
Svar #1
Du kan använda {{ variable }} var som helst i din mall, inte bara i HTML-delen. Så detta borde fungera:
<html>
<head>
<script>
var someJavaScriptVar = '{{ geocode[1] }}';
</script>
</head>
<body>
<p>Hello World</p>
<button onclick="alert('Geocode: {{ geocode[0] }} ' + someJavaScriptVar)" />
</body>
</html>
Tänk på det som en tvåstegsprocess: Först genererar Jinja (mallmotorn som Flask använder) din textutdata. Detta skickas till användaren som kör JavaScriptet han ser. Om du vill att din Flask-variabel ska vara tillgänglig i JavaScript som en array, måste du generera en arraydefinition i din output:
<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 erbjuder också mer avancerade konstruktioner från Python, så du kan förkorta det till:
<html>
<head>
<script>
var myGeocode = [{{ ', '.join(geocode) }}];
</script>
</head>
<body>
<p>Hello World</p>
<button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>
Du kan också använda for-loopar, if-satser och många fler, se Jinja2-dokumentationen för mer information.
Ta också en titt på Fords svar som påpekar tojson-filtret, vilket är ett tillägg till Jinja2:s standarduppsättning av filter.
Redigera nov 2018: tojson ingår nu i Jinja2s standarduppsättning av filter.
Svar #2
Det idealiska sättet att få nästan vilket Python-objekt som helst till ett JavaScript-objekt är att använda JSON. JSON är utmärkt som ett format för överföring mellan system, men ibland glömmer vi att det står för JavaScript Object Notation. Detta innebär att injicera JSON i mallen är samma sak som att injicera JavaScript-kod som beskriver objektet.
Flask tillhandahåller ett Jinja-filter för detta: tojson skriver ut strukturen till en JSON-sträng och markerar den som säker så att Jinja inte autoescapar den.
<html>
<head>
<script>
var myGeocode = {{ geocode|tojson }};
</script>
</head>
<body>
<p>Hello World</p>
<button onclick="alert('Geocode: ' + myGeocode[0] + ' ' + myGeocode[1])" />
</body>
</html>
Detta fungerar för vilken Python-struktur som helst som kan serialiseras till JSON:
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);
Svar #3
Att använda ett dataattribut på ett HTML-element undviker att behöva använda inline-skript, vilket i sin tur innebär att du kan använda striktare CSP-regler för ökad säkerhet.
Ange ett dataattribut på följande sätt:
<div id="mydiv" data-geocode='{{ geocode|tojson }}'>...</div>
Då får du åtkomst till det i en statisk JavaScript-fil på följande sätt:
// Raw JavaScript
var geocode = JSON.parse(document.getElementById("mydiv").dataset.geocode);
// jQuery
var geocode = JSON.parse($("#mydiv").data("geocode"));
Svar #4
Alternativt kan du lägga till en endpoint för att returnera din variabel:
@app.route("/api/geocode")
def geo_code():
return jsonify(geocode)
Gör sedan en XHR för att hämta det:
fetch('/api/geocode')
.then((res)=>{ console.log(res) })
