Django模板变量和Javascript


219

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

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

Answers:


291

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

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

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

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


29
请注意,尽管根据此解决方案,这很容易受到注入攻击
Casebash 2010年

13
@Casebash:对于这样的场合escapejs过滤器存在:escapejs('<>') -> u'\\u003C\\u003E'
托马斯杰林斯基

24
仅供参考:如果“ someDjangoVariable”恰好是JSON,请确保使用{{someDjangoVariable | safe}}删除“
2012年

4
此答案仅适用于简单的变量,不适用于复杂的数据结构。在这种情况下,最简单的解决方案是添加客户端代码以遍历数据结构并在Javascript中构建类似的代码。如果复杂的数据结构为JSON格式,则另一种解决方案是对其进行序列化,将序列化的JSON以服务器端代码的形式传递给Django模板,并以客户端代码中的javascript对象的形式反序列化JSON。下面的一个答案提到了这种替代方法。
艾伦·

14
如果将javascript写入其他文件怎么办?
the_unknown_spirit

64

注意检查票证#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>

3
很好,因为它只允许将一些Django模板输入变量复制到Javascript,并且服务器端代码不需要知道Javascript必须使用哪些数据结构,因此在呈现Django模板之前将其转换为JSON。要么使用这个,要么总是将所有Django变量复制到Javascript。
艾伦·


1
@JorgeOrpinel不,不一样。safe仅将值标记为安全,而没有适当的转换和转义。
Yaroslav Admin

2
然后如何在django模板中显示变量?
kbdev

1
@Sandi返回时,通常在单独的JS文件中包含一个小部件并在页面源代码中对其进行初始化是很常见的。假设您function myWidget(config) { /* implementation */ }在JS文件中声明,然后在上使用myWidget({{ pythonConfig | js }})。但是您不能在JS文件中使用它(如您所注意到的),因此它有其局限性。
Yaroslav Admin

51

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

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

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

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

3
但是要小心。根据您使用变量/表格的方式,用户可以输入他们想要的任何内容。
2012年

3
您可能还需要您输入字段只读设置(见这个链接w3schools.com/tags/att_input_readonly.asp
NU珠峰

如果这不会改变数据库或不会将其发送到数据库查询,则可以。@AndyL
James111 '16

3
伙计们...用户无论如何都可以做他们想做的事情。如今,浏览器借助功能齐全的DOM检查器和调试工具使操作变得如此简单。故事的寓意:在服务器上进行所有数据验证。
user2867288

1
请任何人告诉我您将如何在外部JavaScript文件中访问该变量?
Ahtisham '17


10

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

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

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

希望能帮助到你!


不要使用它,它容易受到脚本注入(XSS)的攻击。
pcworld

8

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


1
请注意,自django 1.7起,'simplejson'成为'json'。
Fiveclubs 2015年

4

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

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

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

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


1
我们该如何克服呢?
卡萨托·托斯

2
为了克服这个问题,可以在包含静态Javascript文件之前放置全局Javascript变量,如所示示例所示。您的静态Javascript文件将可以通过这种方式访问​​所有全局变量。
Bobort

不要使用它,它容易受到脚本注入(XSS)的攻击。
pcworld

他们可以在服务器端验证数据。
穆罕默德·法赞

4

我也一直在为此苦苦挣扎。从表面上看,上述解决方案应该可行。但是,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照常进行。当然,这只是关于获取内容。关于安全性,只需遵循其他答案即可。


您可能要使用.textContent而不是.innerHTML,因为否则,经过HTML编码的实体也将成为JS变量的一部分。但是即使那样也可能无法以1:1的比例复制(我不确定)。
pcworld

澄清一下。我使用一种类似的方法来捕获变量中的字段值(使用在表单中动态创建的ID),并且该方法有效(但仅适用于一个formset row)。我无法解决的问题是,从formset字段的所有行中捕获值,这些行是手动填充的(即在使用for loop的html表中)。正如您将看到的那样,仅将最后一个表单集行的变量传递给变量,并且随着for循环在表单集行中进行处理,之前的值将被后者的值覆盖。有办法解决吗?
user12379095

3

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

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

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


2

请注意,如果要将变量传递给外部.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

全局声明变量的部分实际上很有帮助。
拉胡尔

如果您将数据从上述模板中渲染到js变量中,则必须渲染到同一页面(将它们设为全局),而其他代码将转到单独的js文件中。在服务器端,必须有有效的数据,因为用户可以从浏览器进行更改。
穆罕默德·法赞

1

我在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>

0

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

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>

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


仅在确定aaa仅包含数字时才使用此选项,否则可以使用XSS(脚本注入)。
pcworld

0

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 }}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.