Skip to content

Commit 3293dfd

Browse files
delsimGibbsConsulting
authored andcommitted
Add admin functionality to register new apps (#197)
* Add check of status and a button to load known local instances * Update model * Added missing demo pages * Add test of app insertion view'
1 parent e9cd4ef commit 3293dfd

File tree

8 files changed

+88
-3
lines changed

8 files changed

+88
-3
lines changed

django_plotly_dash/dash_wrapper.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ def all_apps():
6060
'Return a dictionary of all locally registered apps with the slug name as key'
6161
return usable_apps
6262

63+
def get_local_stateless_list():
64+
"""Return a list of all locally registered stateless apps
65+
"""
66+
return list(usable_apps)
67+
6368
def get_local_stateless_by_name(name):
6469
'''
6570
Locate a registered dash app by name, and return a DjangoDash instance encapsulating the app.

django_plotly_dash/models.py

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,24 @@
2323
'''
2424

2525
import json
26+
import logging
2627

2728
from django.db import models
2829
from django.contrib import admin
2930
from django.utils.text import slugify
3031
from django.shortcuts import get_object_or_404
3132

32-
from .dash_wrapper import get_local_stateless_by_name
33+
from .dash_wrapper import get_local_stateless_by_name, get_local_stateless_list
34+
35+
36+
logger = logging.getLogger(__name__)
37+
3338

3439
def get_stateless_by_name(name):
3540
'Locate stateless app instance given its name'
3641
return get_local_stateless_by_name(name)
3742

43+
3844
class StatelessApp(models.Model):
3945
'''
4046
A stateless Dash app. An instance of this model represents a dash app without any specific state
@@ -78,11 +84,34 @@ def find_stateless_by_name(name):
7884
dsa_app.save()
7985
return dash_app
8086

87+
88+
def check_stateless_loaded():
89+
for ua in get_local_stateless_list():
90+
try:
91+
find_stateless_by_name(ua)
92+
except:
93+
logger.warning("django-plotly-dash: Unable to create stateless instance: "+str(ua))
94+
95+
8196
class StatelessAppAdmin(admin.ModelAdmin):
8297
'Admin for StatelessApp ORM model instances'
8398
list_display = ['app_name', 'slug',]
8499
list_filter = ['app_name', 'slug',]
85100

101+
def check_registered(modeladmin, request, queryset):
102+
# Check all existing apps, keep if OK
103+
for sa in queryset.all():
104+
try:
105+
q = sa.as_dash_app()
106+
except:
107+
logger.warnng("django-plotly-dash: Unable to load stateless app: "+str(sa))
108+
109+
110+
check_registered.short_description = "Check stateless apps"
111+
112+
actions = [check_registered,]
113+
114+
86115
class DashApp(models.Model):
87116
'''
88117
An instance of this model represents a dash application and its internal state
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{% extends "admin/change_list.html" %}
2+
{% load i18n admin_urls %}
3+
4+
{% block object-tools-items %}
5+
<li>
6+
<a href="{% url 'the_django_plotly_dash:add_stateless_apps' %}" class="addlink">
7+
{% blocktrans with cl.opts.verbose_name as name %}Find Apps{% endblocktrans %}
8+
</a>
9+
</li>
10+
<li>
11+
{% url cl.opts|admin_urlname:'add' as add_url %}
12+
<a href="{% add_preserved_filters add_url is_popup to_field %}" class="addlink">
13+
{% blocktrans with cl.opts.verbose_name as name %}Add {{ name }}{% endblocktrans %}
14+
</a>
15+
</li>
16+
{% endblock %}
17+

django_plotly_dash/tests.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,3 +346,22 @@ def test_finders():
346346
assert dcf is not None
347347
assert dadf is not None
348348
assert daf is not None
349+
350+
@pytest.mark.django_db
351+
def test_app_loading(client):
352+
353+
from django_plotly_dash.models import check_stateless_loaded
354+
from django.urls import reverse
355+
356+
# Function should run wthout raising errors
357+
check_stateless_loaded()
358+
assert True
359+
360+
url = reverse('the_django_plotly_dash:add_stateless_apps')
361+
362+
response = client.post(url)
363+
364+
# This view redirects to the main admin
365+
assert response.status_code == 302
366+
367+

django_plotly_dash/urls.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,15 @@
2828
from django.views.decorators.csrf import csrf_exempt
2929

3030
from .views import routes, layout, dependencies, update, main_view, component_suites, component_component_suites, asset_redirection
31+
from .views import add_stateless_apps
3132

3233
from .app_name import app_name, main_view_label
3334

3435
from .access import process_view_function
3536

36-
urlpatterns = []
37+
urlpatterns = [
38+
path('add_stateless_apps',add_stateless_apps,name='add_stateless_apps'),
39+
]
3740

3841
for base_type, args, name_prefix, url_ending, name_suffix in [('instance', {}, '', '', '', ),
3942
('app', {'stateless':True}, 'app-', '', '', ),

django_plotly_dash/views.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def check_fingerprint(resource):
3737
return resource, None
3838

3939

40-
from .models import DashApp
40+
from .models import DashApp, check_stateless_loaded
4141
from .util import get_initial_arguments, static_path
4242

4343
def routes(*args, **kwargs):
@@ -172,3 +172,8 @@ def asset_redirection(request, path, ident=None, stateless=False, **kwargs):
172172

173173
return redirect(static_path)
174174

175+
def add_stateless_apps(request, **kwargs):
176+
"""Check all registered stateless apps and create ORM entries that are missing"""
177+
check_stateless_loaded()
178+
return redirect('admin:django_plotly_dash_statelessapp_changelist')
179+

docs/demo_notes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ source repository.
1414
#. Simple html injection
1515
#. Bootstrap components
1616
#. Session state storage
17+
#. Local serving of assets
18+
#. Multiple callback values
1719

1820
The templates that drive each of these can be found in
1921
the `github repository <https://github.com/GibbsConsulting/django-plotly-dash/tree/master/demo/demo/templates>`_.

docs/models_and_state.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ The main role of a ``StatelessApp`` instance is to manage access to the associat
3434
exposed through the ``as_dash_app`` member
3535
function.
3636

37+
In the Django admin, an action is provided to check all of the known stateless instances. Those that cannot be instantiated
38+
are logged; this is a useful quick check to see what apps are avalilable. Also, in the same admin an additional button
39+
is provided to create ``StatelessApp`` instances for any known instance that does not have an ORM entry.
40+
41+
3742
The ``DashApp`` model
3843
---------------------
3944

0 commit comments

Comments
 (0)