Django引入外部JQuery静态文件时模板标签无法识别如何解决?
问题原因
Django的模板引擎仅会渲染配置在TEMPLATES目录下的模板文件,static文件夹下的静态JS文件会直接返回给浏览器,不会经过模板引擎解析,因此文件内的{% url %}、{{ csrf_token }}、{% trans %}等模板标签会原样输出,导致请求地址、翻译文案、csrf校验等逻辑失效。
解决方案
核心思路是将所有需要解析的动态参数放在Django模板层渲染,再传给外部静态JS使用,这里提供两种常用实现方案:
方案1:配置参数初始化函数(灵活度最高)
步骤1:改造外部静态JS(static/js/countries.js)
将联动逻辑封装为可接收配置参数的通用函数,移除所有Django模板标签:
function initProvinceDropdown(config) { $("#id_country").change(function(){ const countryId = $(this).val(); $.ajax({ type: "POST", url: config.getProvinceUrl, data: { 'csrfmiddlewaretoken': config.csrfToken, 'country': countryId }, success: function (data){ data.provinces = data.provinces.sort(function(a, b){ if (a[1] < b[1]) return -1; if (a[1] > b[1]) return 1; return 0; }); let html_data = ''; if (data.provinces.length !== 0) { html_data = `<option value="-----">${config.selectStateText}</option>`; data.provinces.forEach(function(item){ html_data += `<option value="${item[0]}">${item[1]}</option>` }); }else{ html_data = `<option value="-----">${config.noStateText}</option>`; } $("#id_province").html(html_data); } }); }); }
步骤2:模板中调用初始化函数
在模板内引入JS后,传入模板渲染生成的动态参数即可:
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="{% static 'js/countries.js' %}"></script> <script> // 所有参数均由Django模板渲染,可正常解析模板标签 initProvinceDropdown({ getProvinceUrl: "{% url 'get-province' %}", csrfToken: "{{ csrf_token }}", selectStateText: "{% trans 'Select State' %}", noStateText: "{% trans 'No states available for this country' %}" }); </script>
方案2:DOM data属性传参(使用更便捷)
如果不想在每个模板写初始化调用,可以将动态参数绑定到DOM元素的自定义属性上,外部JS直接读取属性即可。
步骤1:模板中给DOM加自定义属性
给form标签添加data-*自定义属性,属性值由Django模板渲染:
<form class="" action="" method="post" data-get-province-url="{% url 'get-province' %}" data-csrf-token="{{ csrf_token }}" data-select-state-text="{% trans 'Select State' %}" data-no-state-text="{% trans 'No states available for this country' %}"> <!-- 原有表单内容不变 --> </form>
步骤2:改造外部静态JS(static/js/countries.js)
JS内部直接读取DOM的自定义属性:
$(function() { // 读取form标签上的动态配置 const $form = $('form'); const config = { getProvinceUrl: $form.data('get-province-url'), csrfToken: $form.data('csrf-token'), selectStateText: $form.data('select-state-text'), noStateText: $form.data('no-state-text') }; // 原有联动逻辑不变 $("#id_country").change(function(){ const countryId = $(this).val(); $.ajax({ type: "POST", url: config.getProvinceUrl, data: { 'csrfmiddlewaretoken': config.csrfToken, 'country': countryId }, success: function (data){ data.provinces = data.provinces.sort(function(a, b){ if (a[1] < b[1]) return -1; if (a[1] > b[1]) return 1; return 0; }); let html_data = ''; if (data.provinces.length !== 0) { html_data = `<option value="-----">${config.selectStateText}</option>`; data.provinces.forEach(function(item){ html_data += `<option value="${item[0]}">${item[1]}</option>` }); }else{ html_data = `<option value="-----">${config.noStateText}</option>`; } $("#id_province").html(html_data); } }); }); });
使用该方案时,模板内仅需引入外部JS即可,无需额外写初始化代码:
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script src="{% static 'js/countries.js' %}"></script>
两种方案均实现了JS逻辑的完全复用,不需要在每个页面重复编写联动代码,同时所有动态参数都能正常被Django模板解析。
内容的提问来源于stack exchange,提问作者Danilo
相关产品推荐
相关产品推荐

