Django传递参数到模板中的JavaScript
概述
在用Django进行网络应用开发时,往往通过模板渲染的方式,直接向前端返回html页面。但是,现代的前端页面需要由HTML、CSS和JavaScript合作进行渲染,简单来说,HTML标记页面结构和元素,CSS描述页面样式,JavaScript控制页面的显示逻辑。现代前端页面中大量使用JavaScript,让页面动起来、活起来,是JavaScript 的强项。Django的模板引擎虽然支持一些循环、条件等模板标签及模板过滤器,还允许自定义模板标签和过滤器,但与各种前端框架比起来,终究是太孱弱了,许多事情还是该在前端由JavaScript处理。这里面往往还涉及到项目的长期可维护性,以及保持前后端分工、前后端代码独立演化能力等方面的考量。
这就需要在使用Django模板的时候,把一个 list 或 dict等 JSON对象通过模板传递到网页的 JavaScript,用 JavaScript在前端对数据进行处理, 例如由前端框架进行数据模型和视图的绑定,或由前端JavaScript进行可视化渲染等。这里的重点是,需要由JavaScript对数据进行进一步处理的,而非用Django的模板引擎进行渲染。
两种方法
要实现上述目的,可以采用以下两种方法:
- 一种方法是,在JavaScript中用AJAX向服务器端请求获取参数。服务器提供的HTML页面中,通过JavaScript中提供AJAX逻辑,在前端将服务器提供的HTML页面加载完成后,从前端通过 AJAX 方式向Django服务器提供的API接口发起请求,得到新的list或dict等JSON字符串数据(注意,这里需要在对服务器提供的HTML页面渲染后,再向服务器发送一次请求)并显示在网页上,这种做法特别适合于不刷新整个页面动态加载一些内容。这种做法是前端主动发起AJAX请求,Django则需要提供对应的接口返回JSON字符串格式的响应数据,本文不讨论这种方法。
- 另一种方法是,不用AJAX,直接由服务器端向JavaScript传递参数。服务器提供HTML页面时,在Django的视图函数中,直接将list或dict等数据转换为JSON字符串,传递给模板中的JavaScript,由JavaScript显示在页面上。(注意,这里不需要从前端再次由JavaScript发起AJAX请求,因为数据已经在服务器提供HTML页面时,直接传递给JavaScript进行渲染了。)这种方法是本文要讨论的,Django传递参数到模板中的JavaScript。
Django传参给模板中的JavaScript
简单来讲,Django要传递参数给模板中的JavaScript。JavaScript需要能够获取到参数(例如list或dict等)所对应的JSON字符串。模板中的JavaScript解析此JSON字符串,然后再用数据做进一步的页面渲染。具体实现有两种方式:
- 视图上下文中传递Python对象的JSON字符串,即将Python对象(例如list或字典)转换后得到的JSON字符串作为Python视图上下文参数传递。Django视图中用 json.dumps()将参数转为JSON字符串,并将字符串加入视图函数的上下文字典,JavaScript中通过模板变量+模板过滤器的方式,即{{ variable|escapejs }}或 {{ variable|safe }},获取到JSON字符串,然后用JSON.parse()函数处理此JSON字符串,构造由字符串描述的JavaScript值或对象,然后做进一步的页面渲染。
- 视图上下文中传递Python对象,即直接将Python对象(例如list或字典)作为Python视图上下文参数传递,在模板渲染时再用过滤器转为JSON字符串。先使用json-script模板标签(Django 2.1及更高版本才支持此模板标签)将Python对象输出为包裹在<script>标签中的JSON字符串,在此<script>标签之后的代码,通过此<script>元素ID获取到其中的JSON字符串,然后用JSON.parse()函数处理此JSON字符串,构造出由字符串描述的JavaScript值或对象,然后做进一步的页面渲染。
下面看下两种方式的具体代码。
上下文中传递Python对象的JSON字符串
这种方式中,Django视图中用 json.dumps()将参数转为JSON字符串,并将字符串加入视图函数的上下文字典,这里我们采用极简的方式,即直接在urls.py中返回TemplateView,TemplateView中通过template_name指定模板文件,通过extra_context将JSON字符串传入视图上下文字典。关键代码如下
urls.py
from django.urls import path, include
from django.views.generic.base import TemplateView
import json
urlpatterns = [
path('index/',
TemplateView.as_view(template_name='index.html',
extra_context={
#此处传递转换为json字符串的Python字典
'django_context_json': json.dumps({'json_string': 'Django Context Json String'}),
})),
]
模板文件index.html中,通过模板变量+过滤器的方式获取到JSON字符串,再解析为JSON对象。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="django_context_json_string_div"> Original </div>
<div id="django_context_json_object_div"> Original </div>
<script type="text/javascript">
var json_string = '{{ django_context_json|escapejs }}'; //获取json字符串对象并转义
var json_object = JSON.parse(json_string); //解析json字符串对象得到JavaScript json对象
document.getElementById('django_context_json_string_div').innerHTML = json_string;
document.getElementById('django_context_json_object_div').innerHTML = json_object.json_string;
</script>
</body>
</html>
上面的代码中,Django通过 json.dumps() 将Python字典 {'json_string': 'Django Context Json String'} 转为JSON字符串,传递给上下文参数django_context_json。在渲染index.html模板时,通过{{ django_context_json }}模板变量可以获取到此字符串,由于需要在JavaScript中处理此字符串,故需要用escapejs过滤器进行转义(实测这里用safe过滤器转义也可以),即{{ django_context_json|escapejs }}。外面用单引号引起来成为JavaScript字符串并赋给JavaScript变量json_string。然后用JSON.parse()从此json_string得到JavaScript json对象,后面就可以在JavaScript中根据需要进一步处理和使用数据了。
本例网页显示截图如下:

这样, 就实现了从Django向模板中的JavaScript传递参数。
上下文中传递Python对象
这种方式中,Django视图中将list或dict等Python对象加入视图函数的上下文字典,这里我们仍采用极简的方式,即直接在urls.py中返回TemplateView,TemplateView中通过template_name指定模板文件,通过extra_context将一个字典对象传入视图上下文字典。关键代码如下
urls.py
from django.urls import path, include
from django.views.generic.base import TemplateView
import json
urlpatterns = [
path('index/',
TemplateView.as_view(template_name='index.html',
extra_context={
'django_context_dict':{'python_key': 'python_value'}, #此处直接传递一个Python字典
})),
]
模板文件index.html中,通过用json-script模板标签(Django 2.1及更高版本才支持此模板标签)将Python对象输出为包裹在指定ID的<script>标签中的JSON字符串。之后的JavaScript代码可以根据ID获取到此<script>的文本内容,并用JSON.parse()解析内容得到JavaScript对象。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div id="django_context_json_string_div"> Original </div>
<div id="django_context_json_object_div"> Original </div>
<!-- 下面的json_script过滤器会生成一个html的script元素,id为json-from-django-context-dict,内容django_context_dict转为json后的字符串 -->
{{ django_context_dict|json_script:"json-from-django-context-dict" }}
<script type="text/javascript">
// 从id为json-from-django-context-dict的html元素获取文本内容(json字符串)
var json_string = document.getElementById('json-from-django-context-dict').textContent;
var json_object = JSON.parse(json_string); //解析json字符串对象得到JavaScript json对象
document.getElementById('django_context_json_string_div').innerHTML = json_string;
document.getElementById('django_context_json_object_div').innerHTML = json_object.python_key;
</script>
</body>
</html>
上面的代码中,Django将Python字典 {'python_key': 'python_value'} 传递给上下文参数django_context_dict。在渲染index.html模板时,通过{{ django_context_json }}模板变量可以获取到此字符串,由于需要在JavaScript中处理此字符串,故需要用escapejs过滤器进行转义(实测这里用safe过滤器转义也可以),即{{ django_context_json|escapejs }}。外面用单引号引起来成为JavaScript字符串并赋给JavaScript变量json_string。然后用JSON.parse()从此json_string得到JavaScript json对象,后面就可以在JavaScript中根据需要进一步处理和使用数据了。
本例网页显示截图如下:

这样, 就实现了从Django向模板中的JavaScript传递参数。
总结
Django的模板引擎和视图函数强大而灵活,组合起来能够完成各种目的的任务。在视图上下文中直接传递Python对象,或者传递Python对象所对应的JSON字符串,都能实现Django传递参数到模板中的JavaScript的目的。
冀公网安备 13010402001886号