如何在没有ajax的情况下从Flask返回JSON数据

时间:2014-02-14 21:40:39

标签: python ajax flask jinja2

假设我想使用Flask渲染页面(而不仅仅是JSON),其中包含我从数据库中获取的一些特定数据。例如

display_data.html包括:

<script src='display_data.js'></script>
...
<h1>Data display page!</h1>
<div id="chartContainer"></div>

display_data.js

$(function() {
     draw_chart($("#chartContainer"), json_data); 
     //draw_chart is defined elsewhere and json_data is what I want to pass in
});

的Python:

@app.route('/<data_id>')
def get_display_data_page(data_id):
  data = get_data_by_id(data_id)
  return render_template('display_data.html', data = data)

我认为如果我只想“渲染模板”,我必须在display_data.html以下的地方加入以下内容:

<script>window.json_data = {{ data | tojson | safe}}</script>

这种模式闻起来很糟糕:我将一个对象放在全局命名空间上(这样我的JS文件就可以访问它),将数据显示为纯文本,并将其中的字符串解析为JSON,以便JS可以用它。看起来不好但这确实有用。

另外两个选择:

  1. 使用AJAX返回数据。鉴于这篇文章的标题,我特意试图避免ajax。这样做的原因主要是我正在建立一个移动网站,并希望减少ping回服务器的数量。我也在思考(也许更多的形而上学)关于封装页面:一旦你拥有它,你就拥有了所有这些。

  2. 通过Flask和Jinja呈现我的JS文件。这看起来很糟糕,因为我必须编写一个路由并根据我在get_display_data_page中的逻辑来渲染JS:通过其id等查找数据。代码重复和动态JS对我来说听起来像是大禁忌。

  3. 这样做有没有已知的模式?

1 个答案:

答案 0 :(得分:1)

如果您不想,则无需在全局范围内保留数据。在您的模板中,您可以执行以下操作:

<script>
function registerTask(f, args) {
  $(function() {
    f.call(this, args);
  });
}

{% for name, args in js_tasks %}
  registerTask({{name}}, {{ args | tojson | safe }});
{% endfor %}
</script>

然后,在您的JS文件中,重新定义draw_chart以获取数据(或者将其用作您的任务注册表名称的包装器):

function draw_chart_task(data) {
  draw_chart($('#chartContainer'), data);
}

最后,在您的控制器中,只需将数据和任务名称作为元组提供:

return render_template('display_data.html', js_tasks=[('draw_chart_task', data)])

这确保您的JavaScript不仅仅是将其依赖项从全局范围中删除,而且您不会进行额外的网络调用。

数据在页面的原始文本输出中可见,但如果您也进行了AJAX调用,则可以看到该数据,您只需查看浏览器开发人员工具的其他面板即可查看。