Django模板变量和Javascript

AlM*_*ean 199 javascript python django google-app-engine django-templates

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

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

S.L*_*ott 269

{{variable}}直接代入HTML.做一个观察源; 它不是"变量"或类似的东西.它只是渲染文本.

话虽如此,您可以将这种替换放入JavaScript中.

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}";
</script>
Run Code Online (Sandbox Code Playgroud)

这为您提供了"动态"javascript.

  • 请注意,根据[此解决方案](http://stackoverflow.com/questions/298772/django-template-variables-and-javascript/1187881#1187881),这很容易受到注入攻击 (26认同)
  • 只是添加到此参考:如果"someDjangoVariable"碰巧是JSON,请务必使用{{someDjangoVariable | safe}}来删除" (21认同)
  • @Casebash:对于这种情况,`escapejs`过滤器存在:`escapejs('<>') - > u'\\ u003C \\ u003E'` (13认同)
  • 如果javascript是用不同的文件写的呢? (13认同)
  • 这个答案只适用于一个简单的变量,它不适用于复杂的数据结构.在这种情况下,最简单的解决方案是添加客户端代码以遍历数据结构并在Javascript中构建类似的数据结构.如果复杂数据结构是JSON格式,另一种解决方案是序列化它,将序列化的JSON传递给服务器端代码中的Django模板,并在客户端代码中的javascript对象中反序列化JSON.下面的一个答案提到了这个选择. (4认同)
  • 10年后,Django为此专门引入了内置模板过滤器:https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#json-script (3认同)
  • 请更新此选项以包含| escapejs过滤器,否则您最终可能会在名称等中包含引号字符的变量,这可能会导致XSS攻击. (2认同)
  • 所以最好的解决方案是使用`var a = {{someDjangoVariable | escapejs | safe}}"`然后呢? (2认同)

Yar*_*min 60

小心检查故障#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))
Run Code Online (Sandbox Code Playgroud)

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

// myapp/templates/example.html

{% load js %}

<script type="text/javascript">
    var someVar = {{ some_var | js }};
</script>
Run Code Online (Sandbox Code Playgroud)

  • 这很好,因为它只允许将一些Django模板输入变量复制到Javascript,服务器端代码不需要知道Javascript必须使用哪些数据结构,因此在呈现Django模板之前转换为JSON.要么使用它,要么总是将所有Django变量复制到Javascript. (3认同)
  • @JorgeOrpinel 不,不一样。`safe` 只将值标记为安全,没有适当的转换和转义。 (2认同)
  • 然后如何在Django模板中显示变量? (2认同)

bos*_*co- 47

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

<input type="hidden" id="myVar" name="variable" value="{{ variable }}">
Run Code Online (Sandbox Code Playgroud)

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

var myVar = document.getElementById("myVar").value;
Run Code Online (Sandbox Code Playgroud)

  • 但要警惕.根据您使用变量/表单的方式,用户可以放入他们想要的任何内容. (3认同)
  • 您可能还希望将输入字段设置为只读(请参阅此链接http://www.w3schools.com/tags/att_input_readonly.asp) (2认同)
  • 伙计们......用户可以做他们想做的事情.浏览器现在使用功能齐全的DOM检查器和调试工具变得如此简单.故事的道德:在**服务器上进行所有数据验证**. (2认同)

Jon*_*kas 18

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

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

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


jam*_*day 8

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

  • 这个方法在我关闭django autoescape之后起作用了. (2认同)
  • 请注意,我相信从 django 1.7 开始,“simplejson”变成了“json”。 (2认同)

Ins*_*iak 8

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

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

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

希望能帮助到你!


sha*_*ker 8

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

var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");
Run Code Online (Sandbox Code Playgroud)

Djangoescapejs正确处理引用,JSON.parse()并将字符串转换回 JS 对象。


Jos*_*osh 8

使用内置模板标签json_script从 Django 2.1+ 实现了一个很好的简单方法。一个简单的例子是:

在模板中声明变量:

{{ variable|json_script:'name' }}

然后在您的<script>Javascript 中调用变量:

var js_variable = JSON.parse(document.getElementById('name').textContent);

对于更复杂的变量(如“用户”),使用 Django 的内置序列化程序可能会出现“用户类型的对象不是 JSON 可序列化的”之类的错误。在这种情况下,您可以使用 Django Rest Framework 来允许更复杂的变量。


Con*_*dor 5

我面临着类似的问题,S.Lott 建议的答案对我有用。

<script type="text/javascript"> 
   var a = "{{someDjangoVariable}}"
</script>
Run Code Online (Sandbox Code Playgroud)

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

这仅在您的主模板和 javascript 代码在同一个文件中时才有效。django 团队可能可以解决这个限制。

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

Dan*_*yuk 5

请注意,如果您想将变量传递给外部 .js 脚本,那么您需要在脚本标记之前使用另一个声明全局变量的脚本标记。

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

<script type="text/javascript" src="{% static "scripts/my_script.js" %}"></script>
Run Code Online (Sandbox Code Playgroud)

data 像往常一样在视图中定义 get_context_data

def get_context_data(self, *args, **kwargs):
    context['myVar'] = True
    return context
Run Code Online (Sandbox Code Playgroud)


Sho*_*dde 5

我也一直在为此苦苦挣扎。从表面上看,上述解决方案似乎应该有效。然而,Django 架构要求每个 HTML 文件都有自己的渲染变量(即,{{contact}}渲染为contact.html,而{{posts}}转到,例如,index.html等等)。另一方面,<script>标签出现在{%endblock%}in base.htmlfromcontact.htmlindex.htmlinherit 之后。这基本上意味着任何解决方案包括

<script type="text/javascript">
    var myVar = "{{ myVar }}"
</script>
Run Code Online (Sandbox Code Playgroud)

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

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

// index.html
<div id="myvar">{{ myVar }}</div>
Run Code Online (Sandbox Code Playgroud)

进而:

// somecode.js
var someVar = document.getElementById("myvar").innerHTML;
Run Code Online (Sandbox Code Playgroud)

并像往常一样包括<script src="static/js/somecode.js"></script>在内base.html。当然这只是获取内容。关于安全性,只需遵循其他答案即可。


小智 5

我发现我们可以将 Django 变量传递给 JavaScript 函数,如下所示:

<button type="button" onclick="myJavascriptFunction('{{ my_django_variable }}')"></button>
<script>
    myJavascriptFunction(djangoVariable){
       alert(djangoVariable);
    }
</script>
Run Code Online (Sandbox Code Playgroud)


Sha*_*r.M 5

文档说用于{{ mydata|json_script:"mydata" }}防止代码注入。

这里给出一个很好的例子:

{{ mydata|json_script:"mydata" }}
<script>
    const mydata = JSON.parse(document.getElementById('mydata').textContent);
</script>
Run Code Online (Sandbox Code Playgroud)