django-plotly-dash中实现长任务进度条可行吗?附示例求方案
在django-plotly-dash中实现长任务进度条的方案
一、原生Dash Background Callback方案(可行)
你提供的Dash进度条代码可以适配到django-plotly-dash中,核心是用DjangoDash替代原生dash.Dash初始化应用,并调整任务管理器的配置以适配Django环境。
适配步骤:
配置后台任务管理器
保持Diskcache/Celery的配置逻辑,但注意路径和Celery的Django适配:import os import diskcache from celery import Celery from dash import DiskcacheManager, CeleryManager if 'REDIS_URL' in os.environ: # 复用Django的Celery配置,避免单独初始化的兼容性问题 celery_app = Celery('your_django_project', broker=os.environ['REDIS_URL'], backend=os.environ['REDIS_URL']) background_callback_manager = CeleryManager(celery_app) else: # 缓存路径设置为Django项目可访问目录,确保权限 cache = diskcache.Cache("./django_dash_cache") background_callback_manager = DiskcacheManager(cache)用DjangoDash注册应用
替换原生dash.Dash为django_plotly_dash.DjangoDash:from django_plotly_dash import DjangoDash from dash import Input, Output, html import time app = DjangoDash("ProgressBarApp", background_callback_manager=background_callback_manager) # 原有的layout和callback代码完全复用 app.layout = html.Div( [ html.Div([ html.P(id="paragraph_id", children=["Button not clicked"]), html.Progress(id="progress_bar", value="0"), ]), html.Button(id="button_id", children="Run Job!"), html.Button(id="cancel_button_id", children="Cancel Running Job!"), ] ) @app.callback( output=Output("paragraph_id", "children"), inputs=Input("button_id", "n_clicks"), background=True, running=[ (Output("button_id", "disabled"), True, False), (Output("cancel_button_id", "disabled"), False, True), (Output("paragraph_id", "style"), {"visibility": "hidden"}, {"visibility": "visible"}), (Output("progress_bar", "style"), {"visibility": "visible"}, {"visibility": "hidden"}), ], cancel=Input("cancel_button_id", "n_clicks"), progress=[Output("progress_bar", "value"), Output("progress_bar", "max")], prevent_initial_call=True ) def update_progress(set_progress, n_clicks): total = 5 for i in range(total + 1): set_progress((str(i), str(total))) time.sleep(1) return f"Clicked {n_clicks} times"在Django中集成应用
- 方式一:通过URL直接访问
在urls.py中添加:from django.urls import path from django_plotly_dash.views import add_to_session from .dash_apps import progress_app urlpatterns = [ path('dash/progress/', add_to_session(progress_app.app), name='progress_dash'), ] - 方式二:嵌入到Django模板
在模板中使用模板标签:{% load plotly_dash %} {% plotly_app name="ProgressBarApp" %}
- 方式一:通过URL直接访问
注意事项:
- 执行
python manage.py collectstatic以加载Dash的静态资源。 - Celery worker需配置
DJANGO_SETTINGS_MODULE环境变量,确保和Django共用配置。 - Diskcache目录需保证Django进程和后台任务进程都有读写权限。
二、替代方案(原生Dash方案兼容问题时使用)
如果遇到django-plotly-dash版本对Background Callback支持不完善的情况,可采用Django+Celery+前端轮询/WebSocket的方案。
方案1:Celery+前端轮询
创建进度存储模型
from django.db import models class TaskProgress(models.Model): task_id = models.CharField(max_length=255, unique=True) progress = models.IntegerField(default=0) total = models.IntegerField(default=100) status = models.CharField(max_length=20, choices=[('running', 'Running'), ('completed', 'Completed'), ('cancelled', 'Cancelled')], default='running')编写Celery任务
from celery import shared_task from .models import TaskProgress import time @shared_task(bind=True) def long_running_task(self, task_id): progress_obj = TaskProgress.objects.get(task_id=task_id) total = 5 for i in range(total + 1): if not self.request.is_aborted(): progress_obj.progress = i progress_obj.total = total progress_obj.save() time.sleep(1) else: progress_obj.status = 'cancelled' progress_obj.save() return progress_obj.status = 'completed' progress_obj.save()Django视图处理任务交互
编写启动、取消、查询进度的API视图,前端通过AJAX轮询获取进度并更新进度条(可参考常规Django API+JS轮询实现)。
方案2:Django Channels+WebSocket实时更新
通过WebSocket实现进度的实时推送,无需前端轮询,适合高实时性需求。需配置Django Channels通道层,Celery任务执行时通过Channels发送进度消息到前端页面。
内容的提问来源于stack exchange,提问作者Codein
相关产品推荐
相关产品推荐

