Flask의 데이터를 템플릿의 JavaScript로 어떻게 전달할 수 있습니까?


123

내 앱은 사전을 반환하는 API를 호출합니다. 이 dict의 정보를 뷰의 JavaScript로 전달하고 싶습니다. 특히 JS에서 Google Maps API를 사용하고 있으므로 long / lat 정보가 포함 된 튜플 목록을 전달하고 싶습니다. render_templateHTML에서 사용할 수 있도록 이러한 변수를 뷰에 전달 한다는 것을 알고 있지만 템플릿의 JavaScript에 어떻게 전달할 수 있습니까?

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)

답변:


140

{{ variable }}HTML 부분뿐만 아니라 템플릿의 어느 곳에서나 사용할 수 있습니다 . 따라서 이것은 작동합니다.

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

2 단계 프로세스로 생각하십시오. 첫째, Jinja (Flask가 사용하는 템플릿 엔진)는 텍스트 출력을 생성합니다. 이것은 그가 보는 JavaScript를 실행하는 사용자에게 전송됩니다. Flask 변수를 JavaScript에서 배열로 사용하려면 출력에서 ​​배열 정의를 생성해야합니다.

<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는 또한 Python의 고급 구조를 제공하므로 다음과 같이 단축 할 수 있습니다.

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

for루프, if문 등을 사용할 수도 있습니다. 자세한 내용은 Jinja2 문서 를 참조하세요.

또한 Jinja2의 표준 필터 세트에tojson 추가 된 필터를 지적하는 Ford의 답변을 살펴보십시오 .

2018 년 11 월 편집 : tojson이제 Jinja2의 표준 필터 세트에 포함됩니다.


2
많은 의무가 있습니다, mensi! 그것은 내 초기 생각 이었지만 Flask에 대한 문서는 JS에서도 {{var}} 형식을 사용할 수 있음을 쉽게 명확하게하지 않습니다. 정리해 주셔서 감사합니다.
mea

2
@mea : 템플릿 엔진을 사용하여 임의의 텍스트 기반 파일을 생성 할 수도 있습니다. 또한 TeX 파일 (-> PDF)과 이메일을 동적으로 생성하는데도 사용했습니다. 매우 다재다능합니다.)
mensi

빠른 후속 질문 : JS에서 for 루프를 수행하면 파이썬 변수 (예 : {{geocode [i]}}) 내에서 인덱스 변수를 사용할 수 있습니까?
mea

1
의미가 있지만 게시 한 솔루션은 JS 배열의 내용을 직접 코딩 해야하는 것 같습니다. 변수 길이의 Python 목록을 전달하고 JS for 루프가 길이를 반복 한 다음 JS 배열에 추가 할 수 있도록 프로그래밍 방식으로 더 많이 수행 할 수 있기를 바랐습니다. 내가 충분히 명확하지 않다면 미안하지만 JS와 웹 개발자에게는 다소 녹색입니다.
mea

1
@RocketPingu 데이터를 별도의 파일로 전달하려는 경우 일반적으로 json모듈을 사용 하여 데이터를 json 객체 형태로 덤프 하는 것이 더 쉽습니다
mensi

113

거의 모든 Python 객체를 JavaScript 객체로 가져 오는 이상적인 방법은 JSON을 사용하는 것입니다. JSON은 시스템 간 전송을위한 형식으로 훌륭하지만 때때로 JavaScript Object Notation을 의미한다는 사실을 잊어 버립니다. 즉, JSON을 템플릿에 주입하는 것은 객체를 설명하는 JavaScript 코드를 주입하는 것과 같습니다.

Flask는이를 위해 Jinja 필터를 제공 tojson합니다. 구조를 JSON 문자열로 덤프하고 Jinja가 자동 이스케이프하지 않도록 안전하다고 표시합니다.

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

이것은 JSON 직렬화 가능한 모든 Python 구조에서 작동합니다.

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

4
다음 Uncaught SyntaxError: Unexpected token &에 자바 스크립트 콘솔에 들어갈 때 시도해보세요 .
scharfmn

8
나는이 대답이 받아 들여진 대답보다 더 견고하고 논리적이라고 생각합니다.
Konrad

코드 실행 중 오류가 발생했습니다.TypeError: Object of type Undefined is not JSON serializable
jbuddy_13

27

사용하여 데이터 속성을 HTML 요소에하는 회전 수단에 사용할 수있는 인라인 스크립트 사용하는 것을 피한다 엄격한 CSP 규칙을 보안을 강화합니다.

다음과 같이 데이터 속성을 지정하십시오.

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

그런 다음 다음과 같이 정적 JavaScript 파일에서 액세스합니다.

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

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

11

또는 변수를 반환하는 엔드 포인트를 추가 할 수 있습니다.

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

그런 다음 XHR을 수행하여 검색합니다.

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

예, , 일부 아키텍처 (특히 SPA를.)이 당신이 그것을 제공 할 때 페이지에 데이터를 베이킹 대이 일을 몇 가지 단점이 있다는 것을 염두에 적절한 일을하는 방법이 있지만, 곰 : 1. 그것의 느리다. 2. 엉성하게 처리하는 데에도 약간 더 많은 코드가 필요하고 3. UI에서 깔끔하게 처리해야 할 최소한 두 개의 추가 프런트 엔드 상태 (즉, XHR 요청이 아직 진행중인 상태)가 도입됩니다. , 완전히 실패한 경우), 추가 JavaScript 코드가 필요하고 잠재적 인 버그의 추가 소스를 도입합니다.
Mark Amery

3

플라스크를 사용하여 공급되는 스크립트에 변수를 전달하려는 사람들을위한 또 다른 대안으로, 외부 변수를 정의한 다음 스크립트를 다음과 같이 호출하여이 작업을 수행 할 수있었습니다.

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

진자 변수를 입력하면 test123.js작동하지 않고 오류가 발생합니다.


내가 찾던 바로 그것.
shrishinde 07.28 07:28

1
-1; 이 대답은 말이되지 않습니다. 나는 ( "플라스크를 사용하여 제공되는 스크립트"라는 문구 와에서 템플릿 변수를 사용할 수있을 것이라는 당신의 명백한 기대에 근거하여 /static/test123.js) <script>s가 어떻게 src작동 하는지 오해하고 있다고 생각합니다 . 그들은 Flask 기능이 아닙니다. 브라우저 는 이러한 스크립트를 구문 분석 할 때, 스크립트를 얻을 수있는 별도의 HTTP 요청을한다. 스크립트 내용은 Flask에 의해 템플릿에 구워지지 않습니다. 실제로 Flask는 브라우저가 스크립트를 요청할 때까지 브라우저에 템플릿 HTML을 보낸 것 같습니다.
Mark Amery

3

작업 답변은 이미 제공되었지만 플라스크 변수를 사용할 수없는 경우 안전 장치 역할을하는 검사를 추가하고 싶습니다. 사용할 때 :

var myVariable = {{ flaskvar | tojson }};

변수가 존재하지 않게하는 오류가있는 경우 결과 오류로 인해 예기치 않은 결과가 발생할 수 있습니다. 이를 방지하려면 :

{% if flaskvar is defined and flaskvar %}
var myVariable = {{ flaskvar | tojson }};
{% endif %}

2
<script>
    const geocodeArr = JSON.parse('{{ geocode | tojson }}');
    console.log(geocodeArr);
</script>

이것은 jinja2를 사용하여 지오 코드 튜플을 json 문자열로 변환 한 다음 자바 스크립트 JSON.parse가이를 자바 스크립트 배열로 변환합니다.


1
왜 당신은 파이썬에서 JSON 직렬화하지 않습니다
Mojimi

0

글쎄요, 저는이 일에 대한 까다로운 방법이 있습니다. 아이디어는 다음과 같습니다.

<label>, <p>, <input>HTML 본문에 등 보이지 않는 HTML 태그를 만들고 태그 ID에 패턴을 만듭니다. 예를 들어 태그 ID에 목록 색인을 사용하고 태그 클래스 이름에 목록 값을 사용합니다.

여기에 동일한 길이의 maintenance_next [] 및 maintenance_block_time [] 목록이 두 개 있습니다. 플라스크를 사용하여이 두 목록의 데이터를 javascript에 전달하고 싶습니다. 그래서 보이지 않는 레이블 태그를 가져 와서 태그 이름을 목록 인덱스의 패턴으로 설정하고 클래스 이름을 인덱스의 값으로 설정합니다.

{% for i in range(maintenance_next|length): %}
<label id="maintenance_next_{{i}}" name="{{maintenance_next[i]}}" style="display: none;"></label>
<label id="maintenance_block_time_{{i}}" name="{{maintenance_block_time[i]}}" style="display: none;"></label>
{% endfor%}

그런 다음 간단한 자바 스크립트 작업을 사용하여 자바 스크립트에서 데이터를 검색합니다.

<script>
var total_len = {{ total_len }};

for (var i = 0; i < total_len; i++) {
    var tm1 = document.getElementById("maintenance_next_" + i).getAttribute("name");
    var tm2 = document.getElementById("maintenance_block_time_" + i).getAttribute("name");
    
    //Do what you need to do with tm1 and tm2.
    
    console.log(tm1);
    console.log(tm2);
}
</script>


-1

일부 js 파일은 웹 또는 라이브러리에서 가져 오며 직접 작성하지 않습니다. 다음과 같은 변수를 얻는 코드 :

var queryString = document.location.search.substring(1);
var params = PDFViewerApplication.parseQueryString(queryString);
var file = 'file' in params ? params.file : DEFAULT_URL;

이 방법 은 js 파일을 변경하지 않고 (독립성을 유지) 변수를 올바르게 전달합니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.