【问题标题】:How to get JS file to pull data from database如何获取JS文件以从数据库中提取数据
【发布时间】:2019-08-05 18:48:38
【问题描述】:

我是 Django 的新手,正在做一个简单的项目,该项目涉及用户提交的表单和仪表板页面,该页面提供了一些漂亮的可视化图表来总结用户输入的数据。我正在为仪表板页面使用免费模板。它被创意蒂姆称为黑色仪表板。

在我的 HTML 模板中有以下内容

<canvas id="chartBig1"></canvas>

我相信这引用了 JS 文件中有关要显示的图表的信息

下面是我认为html引用的JS文件的sn-p

var myChart = new Chart(ctxGreen, {
  type: 'line',
  data: data,
  options: gradientChartOptionsConfigurationWithTooltipGreen

});



var chart_labels = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'];
var chart_data = [100, 70, 90, 70, 85, 60, 75, 60, 90, 80, 110, 100];


var ctx = document.getElementById("chartBig1").getContext('2d');

数据是静态的。使用我使用 models.py 保存的数据显示这些图表的最佳方式是什么。可以直接把数据拉到JS文件里吗?

谢谢

【问题讨论】:

    标签: javascript django sqlite templates django-models


    【解决方案1】:

    执行此操作的标准方法是创建一个 django 模板过滤器,将上下文变量转换为 json(根据设计,它是有效的有效 javascript 值文字):

    from django.import template
    from django.utils.safestring import mark_safe
    import json
    register = template.Library
    
    @register.filter
    def jsonval(val):
        """Output ``val`` as a (json) value suitable for assigning to variables in
           javascript::
    
               var js_var = {{ python_var|jsonval }};
    
        """
        return mark_safe(json.dumps(val, sort_keys=True, indent=4))
    

    这需要放在您应用的 templatetags 文件夹中,通常在一个名为 myapp_tags.py 的文件中(在文档中阅读有关创建自定义过滤器的更多信息:https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/)。

    在您的模板中,您需要先加载过滤器,然后才能使用它:

    {% load myapp_tags %}
    ....
    var chart_data = {{ chart_data|jsonval }};
    ....
    

    在您看来,您需要确保 chart_data 上下文变量是 json 可序列化的——即。仅包含列表、字典、字符串、数字、布尔值和无(即没有 Django 查询集等)。 json 文档包含有关绕过此限制的方法的信息,请参阅 https://docs.python.org/3/library/json.html -- 在“扩展 JSONEncoder”下;这可能需要在 js 端进行类似的解码步骤:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse#Using_the_reviver_parameter 尽管这会使您的过滤器标签更加复杂:

    @register.simple_tag
    def json_setup():
        return """
        var my_reviver = function (key, val) {
            if (typeof val === 'string' && val.startsWith("@date:")) {
                var dateval = val.slice("@date:".length);
                return new Date(Date.parse(dateval));
            }
            return val;  // else
        };
        """
    
    class MyEncoder(json.JSONEncoder):
        def default(self, obj):
            if isinstance(obj, datetime.date):
                return "@date:" + obj.isoformat()   # e.g. "@date:2019-03-15"
            if isinstance(obj, decimal.Decimal):
                return float(obj)
            # ..etc..
            # Let the base class default method raise the TypeError
            return json.JSONEncoder.default(self, obj)
    
    @register.filter
    def jsonval(val):
        return mark_safe('JSON.parse("%s", my_reviver)' % json.dumps(val, cls=MyEncoder, sort_keys=True))
    

    和你的模板:

    {% load myapp_tags %}
    {% json_setup %}
    ....
    var chart_data = {{ chart_data|jsonval }};
    ....
    

    【讨论】:

    【解决方案2】:

    你可以把 JS sn-p 移动到你的 html 模板中并在文件中删除它,然后像这样渲染数据:

    # template.html
    <body>
      ...
      <script>
        var myChart = new Chart(ctxGreen, {
          type: 'line',
          data: data,
          options: gradientChartOptionsConfigurationWithTooltipGreen
        });
    
        var chart_labels = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'];
        var chart_data = [
          {% for instance in queryset %}
            {{ instance.data_point }}{% if not forloop.last %}, {% endif %}
          {% endfor %}
        ];
    
        var ctx = document.getElementById("chartBig1").getContext('2d');
    
      </script>
    </body>
    
    

    【讨论】:

    • @thebjorn 逗号位于 for 循环内,因此如果查询集为空,则 for 循环不会运行并且逗号不会被渲染。此外,数组中的尾随逗号在 javascript 中没有负面影响,例如 var data = [1, 2, 3,];
    • @thebjorn 如果你不喜欢后面的逗号因为美观,你可以这样做:{% for instance in queryset %}{{ instance.data_point }}{% if not forloop.last %}, {% endif %}{% endfor %}
    • @thebjorn 那么您对最好的方法有什么建议吗?在你看来
    • @Pedro 我的错。它曾经是 IE 中的语法错误,但显然他们已经修复了它(耶!)
    • @MatthewMacfarlane 如果您不想使用尾随逗号,请执行以下操作:{% for instance in queryset %}{{ instance.data_point }}{% if not forloop.last %}, {% endif %}{% endfor %}
    【解决方案3】:

    您还可以将您从后端传递给模板的上下文中的数据存储在包含的脚本可访问的变量中。因此,例如,如果您的视图中有一个上下文是

    context = { 'name': name }
    

    在你的模板里面你可以做的脚本标签

    <script>var randomJsVariableName = "{{ name }}";</script>
    

    并且你应该能够在外部 js 文件中访问它,只要它包含在你的模板中,在带有变量的脚本标记之后,即

    <script>var randomJsVariableName = "{{ name }}";</script>
    <script src="externalJsFile.js"></script>
    

    还请记住,如果在您的主要可继承模板中,如果您有一个 js 块,则可以在您当前正在处理的模板中为您的 js 使用块标签。另外作为旁注,我在这里使用var 而不是letconst,因为这是在html 模板中,我不知道您是否以某种方式设置了babel,我相信IE 或Edge不喜欢 let 和 const

    编辑: @thebjorn 说这将返回一个 typeof 字符串时是正确的。您可以将其分配给变量而不使用引号,而只需获取您传递的原始类型,或者您可以传递字符串并在 js 中解析它

    【讨论】:

    • 这将使randomJsVariableName 始终为字符串类型,无论name 在您的上下文中具有什么类型。
    猜你喜欢
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    • 2019-05-07
    • 2014-05-06
    • 1970-01-01
    • 2023-03-11
    • 2020-10-14
    • 2018-07-14
    相关资源
    最近更新 更多