Приложение Django с обратным вызовом Plotly/Dash и Celery/Redis
У меня есть проект Django, в котором одно из моих приложений обеспечивает интерактивную визуализацию данных с помощью Dash/Plotly и развернуто на Heroku. Поскольку моя база данных увеличилась, время, необходимое для сбора соответствующих данных, их нормализации и построения графиков, теперь часто превышает 30 секунд, поэтому запросы выполняются по таймеру, и мои графики больше не отображаются, что печально, потому что они работали отлично :/
Сейчас я пытаюсь использовать Celery, чтобы сбор и нормализация данных передавались на рабочий сервер и выполнялись асинхронно, используя Redis в качестве брокера, но это становится крайне запутанным, поскольку у меня нет опыта работы с этими фреймворками, и я не смог найти пример такого приложения. Ниже я привожу упрощенное и аналогичное приложение без всяких Celery вещей, которое работает именно так, как я хочу (пользователь предоставляет семя, а приложение строит диаграмму рассеяния со случайными числами, сгенерированными из этого семени).
Дерево проекта:
djcel/
djcel/
worker/
dash_apps/
test_apps/
plot.py
templates/
worker/
scatter_plot.html
urls.py
views.py
А основными файлами являются:
plot.py
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
from django_plotly_dash import DjangoDash
import plotly.graph_objects as go
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = DjangoDash('ScatterPlot', external_stylesheets=external_stylesheets)
def scatter_plot(seed):
"""
Plots random data.
"""
import numpy as np
np.random.seed(seed=seed)
x = np.arange(1,1000,1)
y = np.random.rand(1000)
fig = go.Figure(data=go.Scatter(x=x, y=y, mode='markers'))
return fig
seeds = [11, 42, 97, 1001]
app.layout = lambda: html.Div([
html.Div([
html.Div([
dcc.Dropdown(
id='seed',
options=[{'label': i, 'value': i} for i in seeds],
placeholder='Select the seed...'
)
],
style={'width': '30%', 'display': 'inline-block'})
]),
dcc.Graph(id='Scatter-plot'),
])
@app.callback(
Output('Scatter-plot', 'figure'),
Input('seed', 'value')
)
def update_graph(seed):
if(seed):
return scatter_plot(seed)
else:
return go.Figure()
views.py
from django.shortcuts import render
from plotly.offline import plot
from django.views.decorators.cache import cache_page
def scatter_plot_dispatch(requests):
return render(requests, 'worker/scatter_plot.html')
urls.py
from django.urls import path
from . import views
from .dash_apps.test_apps import plot
urlpatterns = [
path('scatterplot/', views.scatter_plot_dispatch, name="worker.scatter_plot"),
]
scatter_plot.html
{% extends "base.html" %}
{% block content %}
{% load plotly_dash %}
<br>
<div class="{% plotly_class name="ScatterPlot" %} card" style="height:100%; width:100%">
{% plotly_app name="ScatterPlot" ratio=0.85 %}
</div>
{% endblock %}
Я хотел бы запускать scatter_plot
асинхронно, и чтобы мое представление обновлялось результирующим объектом фигуры, когда задача будет выполнена. Я знаю, как отправлять задания через Celery/Redis и как проверять их статус, но мне трудно соединить части из-за обратного вызова DjangoDash. Как я могу сделать так, чтобы обратный вызов сразу же возвращал сообщение, предупреждая пользователя о том, что построение графика может занять до минуты, а затем автоматически обновлял его, когда задача будет выполнена? Есть идеи? Я пытаюсь разобраться в этом уже довольно долгое время. Буду рад предоставить любую дополнительную информацию. Спасибо!!!