当我使用 Django 模板渲染器渲染页面时,我可以传入一个包含各种值的字典变量,以使用 {{ myVar }}
在页面中操作它们。
有没有办法在 Javascript 中访问相同的变量(也许使用 DOM,我不知道 Django 如何使变量可访问)?我希望能够根据传入的变量中包含的值使用 AJAX 查找来查找详细信息。
{{variable}}
直接替换为 HTML。做一个视图源;它不是“变量”或类似的东西。它只是呈现的文本。
话虽如此,您可以将这种替换放入您的 JavaScript 中。
<script type="text/javascript">
var a = "{{someDjangoVariable}}";
</script>
这为您提供了“动态”javascript。
注意 请查看票 #17419,了解有关将类似标签添加到 Django 核心中的讨论以及使用此模板标签和用户生成的数据可能引入的 XSS 漏洞。来自 amacneil 的 Comment 讨论了票证中提出的大部分问题。
我认为最灵活、最方便的方法是为要在 JS 代码中使用的变量定义模板过滤器。这使您可以确保您的数据被正确转义,并且您可以将其用于复杂的数据结构,例如 dict
和 list
。这就是为什么我写这个答案,尽管有很多赞成的答案。
这是模板过滤器的示例:
// 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>
safe
仅将值标记为安全,没有适当的转换和转义。
function myWidget(config) { /* implementation */ }
,然后在使用 myWidget({{ pythonConfig | js }})
的某些页面上使用它。但是您不能在 JS 文件中使用它(如您所见),因此它有其局限性。
对我有用的解决方案是使用模板中的隐藏输入字段
<input type="hidden" id="myVar" name="variable" value="{{ variable }}">
然后以这种方式在javascript中获取值,
var myVar = document.getElementById("myVar").value;
从 Django 2.1 开始,专门为此用例引入了一个新的内置模板标记:json_script
。
https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#json-script
新标签将安全地序列化模板值并防止 XSS。
Django 文档摘录:
将 Python 对象安全地输出为 JSON,包装在标签中,可与 JavaScript 一起使用。
使用内置模板标签 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 来允许更复杂的变量。
这是我正在做的非常容易的事情:我为我的模板修改了我的 base.html 文件并将其放在底部:
{% if DJdata %}
<script type="text/javascript">
(function () {window.DJdata = {{DJdata|safe}};})();
</script>
{% endif %}
然后当我想在 javascript 文件中使用变量时,我创建一个 DJdata 字典并通过 json 将其添加到上下文中:context['DJdata'] = json.dumps(DJdata)
希望能帮助到你!
对于以文本形式存储在 Django 字段中的 JavaScript 对象,它需要再次成为动态插入到页面脚本中的 JavaScript 对象,您需要同时使用 escapejs
和 JSON.parse()
:
var CropOpts = JSON.parse("{{ profile.last_crop_coords|escapejs }}");
Django 的 escapejs
正确处理引用,JSON.parse()
将字符串转换回 JS 对象。
对于字典,最好先编码为 JSON。您可以使用 simplejson.dumps(),或者如果您想从 App Engine 中的数据模型进行转换,您可以使用 GQLEncoder 库中的 encode()。
请注意,如果要将变量传递给外部 .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
我面临着类似的问题,S.Lott 建议的答案为我工作。
<script type="text/javascript">
var a = "{{someDjangoVariable}}"
</script>
但是,我想在这里指出主要的实现限制。如果您打算将您的 javascript 代码放在不同的文件中,并将该文件包含在您的模板中。这行不通。
这仅在您的主模板和 javascript 代码位于同一文件中时才有效。可能 django 团队可以解决这个限制。
我也一直在为此苦苦挣扎。从表面上看,上述解决方案似乎应该有效。但是,django 架构要求每个 html 文件都有自己的渲染变量(即,{{contact}}
渲染到 contact.html
,而 {{posts}}
渲染到例如 index.html
等等)。另一方面,<script>
标记出现在 contact.html
和 index.html
继承的 base.html
中的 {%endblock%}
之后。这基本上意味着任何解决方案,包括
<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;
并且像往常一样在 base.html
中包含 <script src="static/js/somecode.js"></script>
。当然,这只是关于获取内容。关于安全性,只需遵循其他答案即可。
.textContent
而不是 .innerHTML
,否则获得 HTML 编码的实体也将成为 JS 变量的一部分。但即便如此,它也可能不会以 1:1 的比例复制(我不确定)。
我发现我们可以将 Django 变量传递给 javascript 函数,如下所示:-
<button type="button" onclick="myJavascriptFunction('{{ my_django_variable }}')"></button>
<script>
myJavascriptFunction(djangoVariable){
alert(djangoVariable);
}
</script>
我在 Django 2.1 中使用这种方式并为我工作,这种方式是安全的 (reference):
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>
您可以组装整个脚本,其中您的数组变量在字符串中声明,如下所示,
视图.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>"
获得此字符串后,您必须将其发送到模板
视图.py
return render(request, 'example.html', {"prueba": prueba})
在模板中,您收到它并以文学方式将其解释为 htm 代码,就在您需要它的 javascript 代码之前,例如
模板
{{ prueba|safe }}
下面是代码的其余部分,请记住,示例中使用的变量是 data2
<script>
console.log(data2);
</script>
这样你就可以保留数据的类型,在这种情况下是一种安排
aaa
将仅包含数字时才使用此选项,否则可能会出现 XSS(脚本注入)。
在 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 }}
escapejs
过滤器存在:escapejs('<>') -> u'\\u003C\\u003E'