Django模板变量和Javascript

问题:Django模板变量和Javascript

当我使用Django模板渲染器渲染页面时,可以传入包含各种值的字典变量,以使用来在页面中对其进行操作{{ myVar }}

有没有办法在Javascript中访问相同的变量(也许使用DOM,我不知道Django如何使变量可访问)?我希望能够基于传入的变量中包含的值使用AJAX查找来查找详细信息。

When I render a page using the Django template renderer, I can pass in a dictionary variable containing various values to manipulate them in the page using {{ myVar }}.

Is there a way to access the same variable in Javascript (perhaps using the DOM, I don’t know how Django makes the variables accessible)? I want to be able to lookup details using an AJAX lookup based on the values contained in the variables passed in.


回答 0

{{variable}}直接替换为HTML。查看资料;它不是“变量”或类似的变量。它只是渲染的文本。

话虽如此,您可以将这种替换形式添加到JavaScript中。

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}";
</script>

这为您提供了“动态” javascript。

The {{variable}} is substituted directly into the HTML. Do a view source; it isn’t a “variable” or anything like it. It’s just rendered text.

Having said that, you can put this kind of substitution into your JavaScript.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}";
</script>

This gives you “dynamic” javascript.


回答 1

注意检查票证#17419,以获取有关将类似的标签添加到Django核心中的讨论以及通过将此模板标签与用户生成的数据一起使用而引入的可能的XSS漏洞。amacneil的评论讨论了故障单中提出的大多数问题。


我认为最灵活,方便的方法是为要在JS代码中使用的变量定义模板过滤器。这样可以确保您的数据已正确转义,并且可以将其用于复杂的数据结构,例如dictlist。这就是为什么我写这个答案的原因,尽管有一个被广泛接受的答案。

这是模板过滤器的示例:

// myapp/templatetags/js.py

from django.utils.safestring import mark_safe
from django.template import Library

import json


register = Library()


@register.filter(is_safe=True)
def js(obj):
    return mark_safe(json.dumps(obj))

此模板过滤器将变量转换为JSON字符串。您可以这样使用它:

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>

CAUTION Check ticket #17419 for discussion on adding similar tag into Django core and possible XSS vulnerabilities introduced by using this template tag with user generated data. Comment from amacneil discusses most of the concerns raised in the ticket.


I think the most flexible and handy way of doing this is to define a template filter for variables you want to use in JS code. This allows you to ensure, that your data is properly escaped and you can use it with complex data structures, such as dict and list. That’s why I write this answer despite there is an accepted answer with a lot of upvotes.

Here is an example of template filter:

// myapp/templatetags/js.py

from django.utils.safestring import mark_safe
from django.template import Library

import json


register = Library()


@register.filter(is_safe=True)
def js(obj):
    return mark_safe(json.dumps(obj))

This template filters converts variable to JSON string. You can use it like so:

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>

回答 2

对我有用的解决方案是使用模板中的隐藏输入字段

<input type="hidden" id="myVar" name="variable" value="{{ variable }}">

然后以这种方式在javascript中获取值,

var myVar = document.getElementById("myVar").value;

A solution that worked for me is using the hidden input field in the template

<input type="hidden" id="myVar" name="variable" value="{{ variable }}">

Then getting the value in javascript this way,

var myVar = document.getElementById("myVar").value;

回答 3

从Django 2.1开始,专门针对此用例引入了一个新的内置模板标记:json_script

https://docs.djangoproject.com/zh-CN/3.0/ref/templates/builtins/#json-script

新标签将安全地序列化模板值并防止XSS。

Django文档摘录:

安全地将Python对象作为JSON输出,包装在标记中,可以与JavaScript一起使用。

As of Django 2.1, a new built in template tag has been introduced specifically for this use case: json_script.

https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#json-script

The new tag will safely serialize template values and protects against XSS.

Django docs excerpt:

Safely outputs a Python object as JSON, wrapped in a tag, ready for use with JavaScript.


回答 4

这是我很容易做的事情:我为模板修改了base.html文件,并将其放在底部:

{% if DJdata %}
    <script type="text/javascript">
        (function () {window.DJdata = {{DJdata|safe}};})();
    </script>
{% endif %}

然后,当我想在javascript文件中使用变量时,我创建了一个DJdata字典,并通过json将其添加到上下文中: context['DJdata'] = json.dumps(DJdata)

希望能帮助到你!

Here is what I’m doing very easily: I modified my base.html file for my template and put that at the bottom:

{% if DJdata %}
    <script type="text/javascript">
        (function () {window.DJdata = {{DJdata|safe}};})();
    </script>
{% endif %}

then when I want to use a variable in the javascript files, I create a DJdata dictionary and I add it to the context by a json : context['DJdata'] = json.dumps(DJdata)

Hope it helps!


回答 5

对于字典,最好先编码为JSON。您可以使用simplejson.dumps(),或者如果要从App Engine中的数据模型进行转换,则可以使用GQLEncoder库中的encode()。

For a dictionary, you’re best of encoding to JSON first. You can use simplejson.dumps() or if you want to convert from a data model in App Engine, you could use encode() from the GQLEncoder library.


回答 6

我面临着类似的问题,S.Lott建议的答案为我工作。

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}"
</script>

但是,我想在这里指出主要的实现限制。如果您打算将javascript代码放在其他文件中,然后将该文件包含在模板中。这行不通。

仅当主模板和javascript代码位于同一文件中时,此方法才有效。也许django小组可以解决这个限制。

I was facing simillar issue and answer suggested by S.Lott worked for me.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}"
</script>

However I would like to point out major implementation limitation here. If you are planning to put your javascript code in different file and include that file in your template. This won’t work.

This works only when you main template and javascript code is in same file. Probably django team can address this limitation.


回答 7

我也一直在为此苦苦挣扎。从表面上看,上述解决方案应该可行。但是,django架构要求每个html文件都有其自己的呈现变量(即{{contact}}呈现为contact.html,而呈现{{posts}}给eg index.html等)。另一方面,<script>标记出现{%endblock%}base.htmlfrom的后面contact.htmlindex.html继承。这基本上意味着任何解决方案,包括

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

必然会失败,因为变量和脚本不能共存于同一文件中。

我最终想出并为我工作的一个简单解决方案是,简单地用带有id的标签包装变量,然后在js文件中引用它,如下所示:

// index.html
<div id="myvar">{{ myVar }}</div>

然后:

// somecode.js
var someVar = document.getElementById("myvar").innerHTML;

并且只包含<script src="static/js/somecode.js"></script>base.html照常进行。当然,这只是关于获取内容。关于安全性,只需遵循其他答案即可。

I’ve been struggling with this too. On the surface it seems that the above solutions should work. However, the django architecture requires that each html file has its own rendered variables (that is, {{contact}} is rendered to contact.html, while {{posts}} goes to e.g. index.html and so on). On the other hand, <script> tags appear after the {%endblock%} in base.html from which contact.html and index.html inherit. This basically means that any solution including

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

is bound to fail, because the variable and the script cannot co-exist in the same file.

The simple solution I eventually came up with, and worked for me, was to simply wrap the variable with a tag with id and later refer to it in the js file, like so:

// index.html
<div id="myvar">{{ myVar }}</div>

and then:

// somecode.js
var someVar = document.getElementById("myvar").innerHTML;

and just include <script src="static/js/somecode.js"></script> in base.html as usual. Of course this is only about getting the content. Regarding security, just follow the other answers.


回答 8

对于以文本形式存储在Django字段中的JavaScript对象,它需要再次成为动态插入页面脚本中的JavaScript对象,您需要同时使用escapejsJSON.parse()

var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");

Django的escapejs句柄正确处理了引号,JSON.parse()并将字符串转换回JS对象。

For a JavaScript object stored in a Django field as text, which needs to again become a JavaScript object dynamically inserted into on-page script, you need to use both escapejs and JSON.parse():

var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");

Django’s escapejs handles the quoting properly, and JSON.parse() converts the string back into a JS object.


回答 9

请注意,如果要将变量传递给外部.js脚本,则需要在脚本标签之前加上另一个声明全局变量的脚本标签。

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>

data 在视图中照常定义 get_context_data

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context

Note, that if you want to pass a variable to an external .js script then you need to precede your script tag with another script tag that declares a global variable.

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>

<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>

data is defined in the view as usual in the get_context_data

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context

回答 10

我在Django 2.1中使用这种方式并为我工作,这种方式很安全(参考)

Django方面:

def age(request):
    mydata = {'age':12}
    return render(request, 'test.html', context={"mydata_json": json.dumps(mydata)})

HTML方面:

<script type='text/javascript'>
     const  mydata = {{ mydata_json|safe }};
console.log(mydata)
 </script>

I use this way in Django 2.1 and work for me and this way is secure (reference):

Django side:

def age(request):
    mydata = {'age':12}
    return render(request, 'test.html', context={"mydata_json": json.dumps(mydata)})

Html side:

<script type='text/javascript'>
     const  mydata = {{ mydata_json|safe }};
console.log(mydata)
 </script>

回答 11

您可以在字符串中声明数组变量的地方组装整个脚本,如下所示,

views.py

    aaa = [41, 56, 25, 48, 72, 34, 12]
    prueba = "<script>var data2 =["
    for a in aaa:
        aa = str(a)
        prueba = prueba + "'" + aa + "',"
    prueba = prueba + "];</script>"

将生成如下字符串

prueba = "<script>var data2 =['41','56','25','48','72','34','12'];</script>"

拥有此字符串后,必须将其发送到模板

views.py

return render(request, 'example.html', {"prueba": prueba})

在模板中,您会收到它,并以书面形式将其解释为htm代码,例如您需要的javascript代码之前

模板

{{ prueba|safe  }}

在代码的其余部分下面,请记住,在示例中使用的变量是data2

<script>
 console.log(data2);
</script>

这样,您将保留数据类型,在这种情况下,这是一种安排

you can assemble the entire script where your array variable is declared in a string, as follows,

views.py

    aaa = [41, 56, 25, 48, 72, 34, 12]
    prueba = "<script>var data2 =["
    for a in aaa:
        aa = str(a)
        prueba = prueba + "'" + aa + "',"
    prueba = prueba + "];</script>"

that will generate a string as follows

prueba = "<script>var data2 =['41','56','25','48','72','34','12'];</script>"

after having this string, you must send it to the template

views.py

return render(request, 'example.html', {"prueba": prueba})

in the template you receive it and interpret it in a literary way as htm code, just before the javascript code where you need it, for example

template

{{ prueba|safe  }}

and below that is the rest of your code, keep in mind that the variable to use in the example is data2

<script>
 console.log(data2);
</script>

that way you will keep the type of data, which in this case is an arrangement


回答 12

Javascript中有两件事对我有用:

'{{context_variable|escapejs }}'

其他:在views.py中

from json import dumps as jdumps

def func(request):
    context={'message': jdumps('hello there')}
    return render(request,'index.html',context)

并在html中:

{{ message|safe }}

There are two things that worked for me inside Javascript:

'{{context_variable|escapejs }}'

and other: In views.py

from json import dumps as jdumps

def func(request):
    context={'message': jdumps('hello there')}
    return render(request,'index.html',context)

and in the html:

{{ message|safe }}