Приложение 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. Как я могу сделать так, чтобы обратный вызов сразу же возвращал сообщение, предупреждая пользователя о том, что построение графика может занять до минуты, а затем автоматически обновлял его, когда задача будет выполнена? Есть идеи? Я пытаюсь разобраться в этом уже довольно долгое время. Буду рад предоставить любую дополнительную информацию. Спасибо!!!

Вернуться на верх