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

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

#1 楼

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

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

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


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

评论


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

– Casebash
2010年6月13日在6:13

@Casebash:在这种情况下,存在escapejs过滤器:escapejs('<>')-> u'\\ u003C \\ u003E'

– TomaszZieliński
2011年8月23日在10:54



Just to add on to this for reference: if the "someDjangoVariable" so happens to be JSON, be sure to use {{ someDjangoVariable|safe }} to remove the "

– Mark
Feb 7 '12 at 14:39

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

–the_unknown_spirit
16年11月15日在7:05

10年后,Django为此专门引入了内置模板过滤器:docs.djangoproject.com/en/2.1/ref/templates/builtins/…

–乔恩·萨卡斯(Jon Sakas)
19年1月19日在19:55

#2 楼

小心检查票证#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>


评论


很好,因为它仅允许将一些Django模板输入变量复制到Javascript,并且服务器端代码无需知道Java脚本必须使用哪些数据结构,因此在渲染Django模板之前将其转换为JSON。要么使用这个,要么总是将所有Django变量复制到Javascript。

–艾伦·埃万格里斯塔(Alan Evangelista)
2014年11月20日19:22

但请注意:stackoverflow.com/questions/23752156/…

– Ciro Santilli郝海东冠状病六四事件法轮功
16年6月3日在14:12

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

– Yaroslav管理员
17年5月30日在10:52

然后如何在Django模板中显示变量?

– KBdev
17年6月14日在17:33

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

– Yaroslav管理员
17/12/21在16:55



#3 楼

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

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


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

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


评论


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

– AndyL
2012年5月2日23:24

您可能还希望将输入字段设置为只读(请参阅此链接w3schools.com/tags/att_input_readonly.asp)

–nu珠穆朗玛峰
2012-12-20 13:53

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

–James111
16-2-8在22:18



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

–user2867288
17-2-18在7:14



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

–阿提沙姆
17年12月21日在12:54

#4 楼

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

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

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

Django文档摘录:


安全将Python对象输出为JSON,包装在标签中,
准备与JavaScript一起使用。


#5 楼

这是我很容易做的事情:
我修改了模板的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
19年8月29日在14:42



#6 楼

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

评论


请注意,自Django 1.7起,'simplejson'成为'json'。

–五家具乐部
2015年9月21日在17:11



#7 楼

我遇到了S.Lott建议的类似问题和回答。

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


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

仅当主模板和javascript代码在同一文件中时,此功能才起作用。
django团队可能可以解决此限制。

评论


我们该如何克服呢?

–Csaba Toth
16年7月8日在18:28

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

– Bobort
17年1月1日在21:33

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

– pcworld
19年8月29日在14:43

他们可以在服务器端验证数据。

–穆罕默德·法赞(Fuedan)
6月14日12:55

#8 楼

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

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


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

评论


这实际上应该是答案。这完美地工作了,没有任何奇怪的手动引号转义。

– derteufelqwe
12月24日23:16

#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


评论


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

–拉胡尔
5月29日23:22

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

–穆罕默德·法赞(Fuedan)
6月14日12:53

#10 楼

我也一直在为此苦苦挣扎。从表面上看,上述解决方案似乎可行。但是,django体系结构要求每个html文件都有其自己的呈现变量(即{{contact}}呈现为contact.html,而{{posts}}呈现为例如index.html等)。另一方面,<script>标签出现在{%endblock%}中的base.html之后,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
19年8月29日在15:11

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

–user12379095
4月25日14:09

#11 楼

从Django 2.1+开始,有一个很好的简便方法,它使用内置模板标签json_script。一个简单的例子是:
在模板中声明变量:
{{ variable|json_script:'name' }}
,然后在<script> Javascript中调用该变量:
var js_variable = JSON.parse(document.getElementById('name').textContent);
使用Django的内置序列化程序,可能会遇到诸如“用户”之类的更复杂的变量,例如“用户类型的对象不可JSON可序列化的对象”之类的错误。在这种情况下,您可以利用Django Rest Framework允许使用更复杂的变量。

#12 楼

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


#13 楼

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


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
19年8月29日在14:47

#14 楼

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


#15 楼

我发现我们可以将Django变量传递给javascript函数,例如:-
<button type="button" onclick="myJavascriptFunction('{{ my_django_variable }}')"></button>
<script>
    myJavascriptFunction(djangoVariable){
       alert(djangoVariable);
    }
</script>


#16 楼

新文档说使用{{ mydata|json_script:"mydata" }}防止代码注入。
此处给出了一个很好的示例:
{{ mydata|json_script:"mydata" }}
<script>
    const mydata = JSON.parse(document.getElementById('mydata').textContent);
</script>