diff --git a/demo/demo/consumers.py b/demo/demo/consumers.py new file mode 100644 index 00000000..f5a21297 --- /dev/null +++ b/demo/demo/consumers.py @@ -0,0 +1,60 @@ +from channels.generic.websocket import WebsocketConsumer + +import json + +ALL_CONSUMERS = [] + +class MessageConsumer(WebsocketConsumer): + def __init__(self, *args, **kwargs): + super(MessageConsumer, self).__init__(*args, **kwargs) + global ALL_CONSUMERS + ALL_CONSUMERS.append(self) + + def connect(self): + self.accept() + + def disconnect(self, close_code): + ac = [] + global ALL_CONSUMERS + for c in ALL_CONSUMERS: + if c != self: + ac.append(c) + ALL_CONSUMERS = ac + + def send_to_widgets(self, channel_name, label, value): + message = json.dumps({'channel_name':channel_name, + 'label':label, + 'value':value}) + global ALL_CONSUMERS + + for c in ALL_CONSUMERS: + c.send(message) + + def receive(self, text_data): + message = json.loads(text_data) + + message_type = message.get('type','unknown_type') + + if message_type == 'connection_triplet': + + channel_name = message.get('channel_name',"UNNAMED_CHANNEL") + uid = message.get('uid',"0000-0000") + label = message.get('label','DEFAULT$LABEL') + + # For now, send the uid as value. This essentially 'resets' the value + # each time the periodic connection announcement is made + self.send_to_widgets(channel_name=channel_name, + label=label, + value=uid) + else: + # Not a periodic control message, so do something useful + # For now, this is just pushing to all other consumers indiscrimnately + + channel_name = message.get('channel_name',"UNNAMED_CHANNEL") + uid = message.get('uid',"0000-0000") + value = message.get('value',{'source_uid':uid}) + label = message.get('label','DEFAULT$LABEL') + + self.send_to_widgets(channel_name=channel_name, + label=label, + value=value) diff --git a/demo/demo/plotly_apps.py b/demo/demo/plotly_apps.py index a6bb63d8..78294c78 100644 --- a/demo/demo/plotly_apps.py +++ b/demo/demo/plotly_apps.py @@ -2,6 +2,8 @@ import dash_core_components as dcc import dash_html_components as html +import dpd_components as dpd + from django_plotly_dash import DjangoDash app = DjangoDash('SimpleExample') @@ -52,3 +54,33 @@ def callback_c(*args,**kwargs): da = kwargs['dash_app'] return "Args are [%s] and kwargs are %s" %(",".join(args),str(kwargs)) +a3 = DjangoDash("Connected") + +a3.layout = html.Div([ + dpd.Pipe(id="dynamic", + value="Dynamo 123", + label="rotational energy", + channel_name="test_widget_channel", + uid="need_to_generate_this"), + dpd.Pipe(id="also_dynamic", + value="Alternator 456", + label="momentum", + channel_name="test_widget_channel", + uid="and_this_one"), + dpd.DPDirectComponent(id="direct"), + dcc.RadioItems(id="dropdown-one",options=[{'label':i,'value':j} for i,j in [ + ("O2","Oxygen"),("N2","Nitrogen"),("CO2","Carbon Dioxide")] + ],value="Oxygen"), + html.Div(id="output-three") + ]) + +@a3.expanded_callback( + dash.dependencies.Output('output-three','children'), + [dash.dependencies.Input('dynamic','value'), + dash.dependencies.Input('dynamic','label'), + dash.dependencies.Input('also_dynamic','value'), + dash.dependencies.Input('dropdown-one','value'), + ]) +def callback_a3(*args, **kwargs): + da = kwargs['dash_app'] + return "Args are [%s] and kwargs are %s" %(",".join(args),str(kwargs)) diff --git a/demo/demo/routing.py b/demo/demo/routing.py new file mode 100644 index 00000000..437bf966 --- /dev/null +++ b/demo/demo/routing.py @@ -0,0 +1,10 @@ +from channels.routing import ProtocolTypeRouter, URLRouter +from channels.auth import AuthMiddlewareStack + +from django.conf.urls import url + +from .consumers import MessageConsumer + +application = ProtocolTypeRouter({ + 'websocket': AuthMiddlewareStack(URLRouter([url('ws/channel', MessageConsumer),])), + }) diff --git a/demo/demo/settings.py b/demo/demo/settings.py index 2371cc06..3fc9af3a 100644 --- a/demo/demo/settings.py +++ b/demo/demo/settings.py @@ -38,6 +38,8 @@ 'django.contrib.messages', 'django.contrib.staticfiles', + 'channels', + 'django_plotly_dash.apps.DjangoPlotlyDashConfig', ] @@ -71,6 +73,7 @@ WSGI_APPLICATION = 'demo.wsgi.application' +ASGI_APPLICATION = 'demo.routing.application' # Database # https://docs.djangoproject.com/en/2.0/ref/settings/#databases @@ -127,6 +130,10 @@ import dash_core_components as dcc _rname = os.path.join(os.path.dirname(dcc.__file__),'..') -for dash_module_name in ['dash_core_components','dash_html_components','dash_renderer',]: +for dash_module_name in ['dash_core_components', + 'dash_html_components', + 'dash_renderer',]: STATICFILES_DIRS.append( ("dash/%s"%dash_module_name, os.path.join(_rname,dash_module_name)) ) +# Fudge to work with channels in debug mode +STATICFILES_DIRS.append(("dash/dpd_components","/home/mark/local/dpd-components/lib")) diff --git a/demo/demo/templates/index.html b/demo/demo/templates/index.html index 74f318dc..fae11fa9 100644 --- a/demo/demo/templates/index.html +++ b/demo/demo/templates/index.html @@ -1,8 +1,16 @@ -{%load plotly_dash%} -
Navigational links : + Main Page + Second Page +
+