Development Tip

Python에서 Jinja2의 목록을 JavaScript로 전달하는 방법

yourdevel 2020. 12. 29. 08:03
반응형

Python에서 Jinja2의 목록을 JavaScript로 전달하는 방법


Python 변수가 있다고 가정 해 보겠습니다.

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

HTML을 렌더링하여 Jinja에 전달하고 somefunction(variable). 의 각 항목을 전달하려고합니다 list_of_items. 나는 다음과 같이 시도했다.

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

Python에서 JavaScript로 목록을 전달할 수 있습니까? 아니면 목록의 각 항목을 루프에서 하나씩 전달해야합니까? 어떻게 할 수 있습니까?


일부 컨텍스트 데이터를 자바 스크립트 코드로 전달하려면 자바 스크립트 (즉, JSON)에서 "이해"할 수있는 방식으로 직렬화해야합니다. 또한 safe데이터가 HTML 이스케이프되지 않도록 Jinja 필터를 사용하여 안전한 것으로 표시해야합니다 .

다음과 같이하면됩니다.

보기

import json

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

템플릿

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

편집-정확한 답변

따라서 원하는 것을 정확하게 얻으려면 (항목 목록을 반복하고 자바 스크립트 함수로 전달) 목록의 모든 항목을 개별적으로 직렬화해야합니다. 코드는 다음과 같습니다.

보기

import json

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

템플릿

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

편집 2

제 예 Flask에서는를 사용합니다. 어떤 프레임 워크를 사용하고 있는지 모르겠지만 아이디어를 얻었습니다. 사용하는 프레임 워크에 적합하도록 만들어야합니다.

편집 3 (보안 경고)

사용자가 제공 한 데이터로는 절대로이 작업을 수행하지 말고 신뢰할 수있는 데이터로만 수행하십시오!

그렇지 않으면 애플리케이션이 XSS 취약성에 노출됩니다!


Flask를 사용하여 비슷한 문제가 발생했지만 JSON에 의존 할 필요가 없었습니다. 방금 목록 letters = ['a','b','c']전달 render_template('show_entries.html', letters=letters)하고 설정했습니다.

var letters = {{ letters|safe }}

내 자바 스크립트 코드에서. Jinja2 교체 {{ letters }}['a','b','c']문자열 배열로 해석되는 자바 스크립트.


Jinja의 tojson필터 로이 작업을 수행 할 수 있습니다.

구조를 JSON으로 덤프하여 <script>큰 따옴표 속성을 제외하고 HTML의 모든 위치에서 태그 [및] 태그에 안전하게 사용할 수 있습니다 .

예를 들어 Python에서 다음을 작성합니다.

some_template.render(list_of_items=list_of_items)

... 또는 Flask 엔드 포인트의 컨텍스트에서 :

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

그런 다음 템플릿에 다음을 작성하십시오.

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

( onclick속성은 작은 따옴표로 묶여 있습니다. 이는 출력에서 문자가 아닌 문자를 |tojson이스케이프 하기 때문에 필요합니다. 즉, 작은 따옴표로 묶인 HTML 속성에서는 안전하게 사용할 수 있지만 큰 따옴표로 묶은 속성에는 사용할 수 없습니다.)'"

또는 list_of_itemsHTML 속성 대신 인라인 스크립트에서 사용하려면 다음 과 같이 작성하십시오.

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

DON'T use json.dumps to JSON-encode variables in your Python code and pass the resulting JSON text to your template. This will produce incorrect output for some string values, and will expose you to XSS if you're trying to encode user-provided values. This is because Python's built-in json.dumps doesn't escape characters like < and > (which need escaping to safely template values into inline <script>s, as noted at https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements) or single quotes (which need escaping to safely template values into single-quoted HTML attributes).

If you're using Flask, note that Flask injects a custom tojson filter instead of using Jinja's version. However, everything written above still applies. The two versions behave almost identically; Flask's just allows for some app-specific configuration that isn't available in Jinja's version.


I can suggest you a javascript oriented approach which makes it easy to work with javascript files in your project.

Create a javascript section in your jinja template file and place all variables you want to use in your javascript files in a window object:

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 will replace values and our appConfig object will be reachable from our other script files:

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

I have seperated javascript code from html documents with this way which is easier to manage and seo friendly.


To add up on the selected answer, I have been testing a new option that is working too using jinja2 and flask:

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

The template:

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

the output of the rendered template:

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

The safe could be added but as well like {{ data | tojson | safe }} but it is working without too.

ReferenceURL : https://stackoverflow.com/questions/15321431/how-to-pass-a-list-from-python-by-jinja2-to-javascript

반응형