FastAPI结合Jinja2模板实现Highcharts图表无刷新自动更新
实现方案
方案1:短轮询(实现成本最低,适合更新频率不高的场景)
步骤1:修改main.py新增数据接口
from fastapi import FastAPI, Request from fastapi.responses import HTMLResponse, JSONResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates import uvicorn import random app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") # 原有页面接口保留 @app.get("/", response_class=HTMLResponse) async def dash(request: Request): data = [random.randint(0,40) for _ in range(12)] return templates.TemplateResponse("dash.html", {"request": request, "title": "my random graph", "tokyo_data": data}) # 新增接口:返回最新的东京温度数据 @app.get("/api/tokyo-data", response_class=JSONResponse) async def get_tokyo_data(): # 这里替换成你的数据库查询逻辑 latest_data = [random.randint(0,40) for _ in range(12)] return {"data": latest_data} if __name__ == '__main__': uvicorn.run("main:app", port=80, host='0.0.0.0', reload = True)
步骤2:修改templates/dash.html添加自动更新逻辑
<html> <head> <title>my random graph</title> <script src = "https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"> </script> <script src = "https://code.highcharts.com/highcharts.js"></script> </head> <body> <div id = "container" style = "width: 550px; height: 400px; margin: 0 auto"></div> <script language = "JavaScript"> // 全局存储图表实例,方便后续更新 let chartInstance = null; $(document).ready(function() { var title = { text: "{{ title }}" }; var credits = { enabled: false }; var subtitle = { text: 'test' }; var xAxis = { categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] }; var yAxis = { title: { text: 'Temperature (\xB0C)' }, plotLines: [{ value: 0, width: 1, color: '#808080' }] }; var tooltip = { valueSuffix: '\xB0C' } var legend = { layout: 'vertical', align: 'right', verticalAlign: 'middle', borderWidth: 0 }; var series = [{ name: 'Tokyo', data: {{ tokyo_data }} }, { name: 'New York', data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5] }, { name: 'Berlin', data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0] }, { name: 'London', data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8] } ]; var json = {}; json.title = title; json.subtitle = subtitle; json.xAxis = xAxis; json.yAxis = yAxis; json.tooltip = tooltip; json.legend = legend; json.series = series; json.credits = credits; // 初始化图表并保存实例 chartInstance = $('#container').highcharts(json); }); // 每3秒拉取一次最新数据,更新图表 setInterval(async () => { if (!chartInstance) return; const res = await fetch('/api/tokyo-data'); const { data: latestData } = await res.json(); // 如果需要仅数据变化时更新,可以在这里和本地存储的上一次数据对比后再执行更新 // 更新东京系列的数据,第二个参数设为true表示自动重绘 chartInstance.series[0].setData(latestData, true); }, 3000); </script> </body> </html>
方案2:WebSocket(实时性更高,适合数据更新频繁的场景)
如果需要数据更新后立即推送,不需要定时轮询,可以用FastAPI的WebSocket支持:
步骤1:修改main.py新增WebSocket路由
from fastapi import FastAPI, Request, WebSocket from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates import uvicorn import random import asyncio from typing import List app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") # 存储所有连接的客户端 active_connections: List[WebSocket] = [] @app.get("/", response_class=HTMLResponse) async def dash(request: Request): data = [random.randint(0,40) for _ in range(12)] return templates.TemplateResponse("dash.html", {"request": request, "title": "my random graph", "tokyo_data": data}) @app.websocket("/ws/data-update") async def websocket_endpoint(websocket: WebSocket): await websocket.accept() active_connections.append(websocket) try: while True: # 这里可以替换为监听数据库更新的逻辑,比如数据库触发器、消息队列通知等 latest_data = [random.randint(0,40) for _ in range(12)] await websocket.send_json({"data": latest_data}) await asyncio.sleep(3) finally: active_connections.remove(websocket) if __name__ == '__main__': uvicorn.run("main:app", port=80, host='0.0.0.0', reload = True)
步骤2:修改前端JS代码替换轮询为WebSocket连接
把之前的setInterval部分替换为以下代码即可:
// 建立WebSocket连接 const ws = new WebSocket(`ws://${window.location.host}/ws/data-update`); ws.onmessage = (event) => { if (!chartInstance) return; const { data: latestData } = JSON.parse(event.data); chartInstance.series[0].setData(latestData, true); };
内容的提问来源于stack exchange,提问作者Zabir Al Nazi Nabil
相关产品推荐
相关产品推荐

