Skip to content

Commit 921df5b

Browse files
author
Mark Gibbs
committed
All stateless apps are now saved into the database when first seen
1 parent def91a6 commit 921df5b

File tree

6 files changed

+95
-96
lines changed

6 files changed

+95
-96
lines changed

django_plotly_dash/migrations/0001_initial.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
# Generated by Django 2.0.5 on 2018-05-10 21:48
1+
# Generated by Django 2.0.5 on 2018-06-08 20:02
22

33
from django.db import migrations, models
4+
import django.db.models.deletion
45

56

67
class Migration(migrations.Migration):
@@ -15,12 +16,25 @@ class Migration(migrations.Migration):
1516
name='DashApp',
1617
fields=[
1718
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
18-
('app_name', models.CharField(max_length=100)),
1919
('instance_name', models.CharField(blank=True, max_length=100, unique=True)),
2020
('slug', models.SlugField(blank=True, max_length=110, unique=True)),
21-
('base_state', models.TextField()),
21+
('base_state', models.TextField(default='{}')),
2222
('creation', models.DateTimeField(auto_now_add=True)),
2323
('update', models.DateTimeField(auto_now=True)),
24+
('save_on_change', models.BooleanField(default=False)),
2425
],
2526
),
27+
migrations.CreateModel(
28+
name='StatelessApp',
29+
fields=[
30+
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
31+
('app_name', models.CharField(max_length=100, unique=True)),
32+
('slug', models.SlugField(blank=True, max_length=110, unique=True)),
33+
],
34+
),
35+
migrations.AddField(
36+
model_name='dashapp',
37+
name='stateless_app',
38+
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='django_plotly_dash.StatelessApp'),
39+
),
2640
]
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Generated by Django 2.0.5 on 2018-06-08 20:03
2+
3+
from django.db import migrations
4+
5+
def addExamples(apps, schema_editor):
6+
7+
DashApp = apps.get_model("django_plotly_dash","DashApp")
8+
StatelessApp = apps.get_model("django_plotly_dash","StatelessApp")
9+
10+
sa1 = StatelessApp(app_name="SimpleExample",
11+
slug="simple-example")
12+
13+
sa1.save()
14+
15+
da1 = DashApp(stateless_app=sa1,
16+
instance_name="SimpleExample-1",
17+
slug="simpleexample-1",
18+
base_state='{"dropdown-color":{"value":"blue"},"dropdown-size":{"value":"small"}}')
19+
20+
da1.save()
21+
22+
23+
def remExamples(apps, schema_editor):
24+
25+
DashApp.objects.all().delete()
26+
StatelessApp.objects.all().delete()
27+
28+
class Migration(migrations.Migration):
29+
30+
dependencies = [
31+
('django_plotly_dash', '0001_initial'),
32+
]
33+
34+
operations = [
35+
migrations.RunPython(addExamples, remExamples),
36+
]

django_plotly_dash/migrations/0002_simple_example_state.py

Lines changed: 0 additions & 28 deletions
This file was deleted.

django_plotly_dash/migrations/0003_auto_20180514_1802.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

django_plotly_dash/migrations/0004_add_stateless_app.py

Lines changed: 0 additions & 21 deletions
This file was deleted.

django_plotly_dash/models.py

Lines changed: 42 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77

88
import json
99

10+
def get_stateless_by_name(name):
11+
return get_local_stateless_by_name(name)
12+
1013
class StatelessApp(models.Model):
1114
'''
12-
A stateless Dash app. An instance of this model represents a dash app witout any specific state
15+
A stateless Dash app. An instance of this model represents a dash app without any specific state
1316
'''
1417
app_name = models.CharField(max_length=100, blank=False, null=False, unique=True)
1518
slug = models.SlugField(max_length=110, unique=True, blank=True)
@@ -22,18 +25,34 @@ def save(self, *args, **kwargs):
2225
self.slug = slugify(self.app_name)
2326
return super(StatelessApp, self).save(*args,**kwargs)
2427

28+
def as_dash_app(self):
29+
dd = getattr(self,'_stateless_dash_app_instance',None)
30+
if not dd:
31+
dd = get_stateless_by_name(self.app_name)
32+
setattr(self,'_stateless_dash_app_instance',dd)
33+
return dd
34+
35+
def find_stateless_by_name(name):
36+
try:
37+
dsa = StatelessApp.objects.get(app_name=name)
38+
return dsa.as_dash_app()
39+
except:
40+
pass
41+
42+
da = get_stateless_by_name(name)
43+
dsa = StatelessApp(app_name=name)
44+
dsa.save()
45+
return da
46+
2547
class StatelessAppAdmin(admin.ModelAdmin):
2648
list_display = ['app_name','slug',]
2749
list_filter = ['app_name','slug',]
2850

29-
def get_stateless_by_name(name):
30-
return get_local_stateless_by_name(name)
31-
3251
class DashApp(models.Model):
3352
'''
3453
An instance of this model represents a dash application and its internal state
3554
'''
36-
app_name = models.CharField(max_length=100, blank=False, null=False, unique=False)
55+
stateless_app = models.ForeignKey(StatelessApp, on_delete=models.PROTECT, unique=False, null=False, blank=False)
3756
instance_name = models.CharField(max_length=100, unique=True, blank=True, null=False)
3857
slug = models.SlugField(max_length=110, unique=True, blank=True)
3958
base_state = models.TextField(null=False, default="{}") # If mandating postgresql then this could be a JSONField
@@ -46,19 +65,12 @@ def __str__(self):
4665

4766
def save(self, *args, **kwargs):
4867
if not self.instance_name:
49-
existing_count = DashApp.objects.filter(app_name=self.app_name).count()
50-
self.instance_name = "%s-%i" %(self.app_name, existing_count+1)
68+
existing_count = DashApp.objects.all().count()
69+
self.instance_name = "%s-%i" %(self.stateless_app.app_name, existing_count+1)
5170
if not self.slug or len(self.slug) < 2:
5271
self.slug = slugify(self.instance_name)
5372
super(DashApp, self).save(*args,**kwargs)
5473

55-
def _stateless_dash_app(self):
56-
dd = getattr(self,'_stateless_dash_app_instance',None)
57-
if not dd:
58-
dd = get_stateless_by_name(self.app_name)
59-
setattr(self,'_stateless_dash_app_instance',dd)
60-
return dd
61-
6274
def handle_current_state(self):
6375
'''
6476
Check to see if the current hydrated state and the saved state are different.
@@ -104,7 +116,7 @@ def current_state(self):
104116
return cs
105117

106118
def as_dash_instance(self):
107-
dd = self._stateless_dash_app()
119+
dd = self.stateless_app.as_dash_app()
108120
base = self.current_state()
109121
return dd.do_form_dash_instance(replacements=base,
110122
specific_identifier=self.slug)
@@ -113,7 +125,7 @@ def _get_base_state(self):
113125
'''
114126
Get the base state of the object, as defined by the app.layout code, as a python dict
115127
'''
116-
base_app_inst = self._stateless_dash_app().as_dash_instance()
128+
base_app_inst = self.stateless_app.as_dash_app().as_dash_instance()
117129

118130
# Get base layout response, from a base object
119131
base_resp = base_app_inst.locate_endpoint_function('dash-layout')()
@@ -135,21 +147,30 @@ def populate_values(self):
135147
@staticmethod
136148
def locate_item(id, stateless=False):
137149
if stateless:
138-
da = get_stateless_by_name(id)
150+
da = find_stateless_by_name(id)
139151
else:
140152
da = get_object_or_404(DashApp,slug=id)
141153

142154
app = da.as_dash_instance()
143155
return da, app
144156

145157
class DashAppAdmin(admin.ModelAdmin):
146-
list_display = ['instance_name','app_name','slug','creation','update','save_on_change',]
147-
list_filter = ['creation','update','save_on_change','app_name',]
158+
list_display = ['instance_name','stateless_app','slug','creation','update','save_on_change',]
159+
list_filter = ['creation','update','save_on_change','stateless_app',]
148160

149161
def _populate_values(self, request, queryset):
150162
for da in queryset:
151163
da.populate_values()
152164
da.save()
153-
_populate_values.short_description = "Populate app"
165+
_populate_values.short_description = "Populate app instance"
166+
167+
def _clone(self, request, queryset):
168+
for da in queryset:
169+
nda = DashApp(stateless_app=da.stateless_app,
170+
base_state=da.base_state,
171+
save_on_change=da.save_on_change)
172+
nda.save()
173+
174+
_clone.short_description = "Clone app instance"
154175

155-
actions = ['_populate_values',]
176+
actions = ['_populate_values','_clone',]

0 commit comments

Comments
 (0)