如何在Django Views加载BigQuery数据期间显示加载页面
问题原因
原来的代码逻辑是等待浏览器加载完完整DOM之后再切换加载状态,但Django传统同步视图的执行流程是:服务端接收到请求→执行BigQuery拉取→渲染完整HTML→将HTML返回给浏览器。也就是说在BigQuery拉取的整个过程中,浏览器还没收到任何响应内容,自然不会显示加载页,等浏览器收到HTML时数据已经拉完了,所以才会出现加载页只闪1-2秒的问题。
解决方案1:AJAX异步拉取(推荐,兼容性最好)
把视图拆分为页面渲染和数据提供两个接口,前端先拿到页面立刻显示加载动画,再异步请求数据,完成后渲染内容。
Django后端代码示例
from django.shortcuts import render from django.http import JsonResponse from .utils import your_bigquery_query_func # 替换为你自己的BigQuery查询方法 # 返回带加载结构的空页面,不执行耗时查询 def data_page(request): return render(request, "data_page.html") # 专门处理数据查询的API接口 def query_data_api(request): # 执行耗时的BigQuery查询 data = your_bigquery_query_func() return JsonResponse({"code": 0, "data": data})
前端页面代码示例(data_page.html)
<!-- 加载元素,默认显示 --> <div class="loading" style="padding: 2rem; text-align: center;">数据加载中,请稍候...</div> <!-- 内容容器,默认隐藏 --> <div id="app" style="display: none;"></div> <script> window.onload = async () => { try { // 请求数据接口 const resp = await fetch("/query_data_api/"); const result = await resp.json(); if (result.code === 0) { // 渲染数据到内容容器,可根据需求替换为你的渲染逻辑 const app = document.querySelector("#app"); app.innerText = JSON.stringify(result.data, null, 2); // 切换显示状态 document.querySelector(".loading").style.display = "none"; app.style.display = "block"; } } catch (e) { document.querySelector(".loading").innerText = "加载失败,请刷新页面重试"; console.error("查询错误:", e); } } </script>
配置Django路由时,需要给上面两个视图分别添加对应的URL映射。
解决方案2:流式响应(无需写额外AJAX请求)
用Django的StreamingHttpResponse先把加载页的内容推送给浏览器,等数据查询完成后再推送内容部分和切换显示的JS代码,适合不想拆分接口的场景。需要注意如果用了GZip等缓存响应的中间件,需要给对应视图排除中间件,否则会等到所有内容生成完才返回。
示例代码
from django.http import StreamingHttpResponse from .utils import your_bigquery_query_func def streaming_data_page(request): def generate_content(): # 第一步:先推送加载页的完整头部和加载元素 yield """ <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>数据查询页</title> </head> <body> <div class="loading" style="padding: 2rem; text-align: center;">数据加载中,请稍候...</div> """ # 第二步:执行耗时的BigQuery查询 data = your_bigquery_query_func() # 第三步:推送内容和切换显示的JS yield f""" <div id="app"> 你的查询结果:{str(data)} </div> <script> document.querySelector('.loading').remove(); </script> </body> </html> """ return StreamingHttpResponse(generate_content())
内容的提问来源于stack exchange,提问作者Owenn
相关产品推荐
相关产品推荐

