Skip to content

Commit 09831c8

Browse files
delsimGibbsConsulting
authored andcommitted
Enable session storage of initial values (#91)
* Relocate store and fetch of initial arguments into util.py * Added flag to use session as an alternative to the cache * Set default to cache not session for initial arguments * Set default to cache * Remove trailing slash * Add tests of initial argument configuration
1 parent f7ed14e commit 09831c8

File tree

7 files changed

+98
-18
lines changed

7 files changed

+98
-18
lines changed

demo/demo/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@
132132
"http_poke_enabled" : True, # Flag controlling availability of direct-to-messaging http endpoint
133133

134134
"view_decorator" : None, # Specify a function to be used to wrap each of the dpd view functions
135+
136+
"cache_arguments" : True, # True for cache, False for session-based argument propagation
135137
}
136138

137139
# Static files (CSS, JavaScript, Images)

django_plotly_dash/templatetags/plotly_dash.py

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,12 @@
2424

2525
# pylint: disable=too-many-arguments, unused-variable, unused-argument, possibly-unused-variable
2626

27-
import uuid
28-
2927
from django import template
30-
from django.core.cache import cache
3128

3229
from django.contrib.sites.shortcuts import get_current_site
3330

3431
from django_plotly_dash.models import DashApp
35-
from django_plotly_dash.util import pipe_ws_endpoint_name, cache_timeout_initial_arguments
32+
from django_plotly_dash.util import pipe_ws_endpoint_name, store_initial_arguments
3633

3734
register = template.Library()
3835

@@ -74,13 +71,7 @@ def plotly_app(context, name=None, slug=None, da=None, ratio=0.1, use_frameborde
7471
height: 100%;
7572
"""
7673

77-
if initial_arguments:
78-
# Generate a cache id
79-
cache_id = "dpd-initial-args-%s" % str(uuid.uuid4()).replace('-', '')
80-
# Store args in json form in cache
81-
cache.set(cache_id, initial_arguments, cache_timeout_initial_arguments())
82-
else:
83-
cache_id = None
74+
cache_id = store_initial_arguments(context['request'], initial_arguments)
8475

8576
da, app = _locate_daapp(name, slug, da, cache_id=cache_id)
8677

django_plotly_dash/tests.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,3 +203,44 @@ def test_injection_updating(client):
203203
assert response3.status_code == 200
204204

205205
assert response3.content.find(b'Test 789 content') > 0
206+
207+
@pytest.mark.django_db
208+
def test_argument_settings(settings, client):
209+
'Test the setting that controls how initial arguments are propagated through to the dash app'
210+
211+
from django_plotly_dash.util import initial_argument_location, store_initial_arguments, get_initial_arguments
212+
213+
assert initial_argument_location()
214+
215+
settings.PLOTLY_DASH = {'cache_arguments': True}
216+
217+
assert initial_argument_location()
218+
219+
test_value = {"test":"first"}
220+
221+
cache_id = store_initial_arguments(None, test_value)
222+
223+
assert len(cache_id) > 10
224+
225+
fetched = get_initial_arguments(None, cache_id)
226+
227+
assert fetched == test_value
228+
229+
settings.PLOTLY_DASH = {'cache_arguments': False}
230+
231+
assert not initial_argument_location()
232+
233+
cache_id2 = store_initial_arguments(client, test_value)
234+
235+
assert len(cache_id2) > 10
236+
237+
assert cache_id != cache_id2
238+
239+
## For some reason, sessions are continually replaced, so lookup here doesnt work
240+
#fetched2 = get_initial_arguments(client, cache_id2)
241+
#assert fetched2 == test_value
242+
243+
assert store_initial_arguments(None, None) is None
244+
assert get_initial_arguments(None, None) is None
245+
assert store_initial_arguments(client, None) is None
246+
assert get_initial_arguments(client, None) is None

django_plotly_dash/urls.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737

3838
for base_type, args, name_prefix, url_ending, name_suffix in [('instance', {}, '', '', '', ),
3939
('app', {'stateless':True}, 'app-', '', '', ),
40-
('instance', {}, '', '/initial/<slug:cache_id>/', '--args', ),
41-
('app', {'stateless':True}, 'app-', '/initial/<slug:cache_id>/', '--args', ),
40+
('instance', {}, '', '/initial/<slug:cache_id>', '--args', ),
41+
('app', {'stateless':True}, 'app-', '/initial/<slug:cache_id>', '--args', ),
4242
]:
4343

4444
for url_part, view_function, name, url_suffix in [('_dash-routes', routes, 'routes', '', ),

django_plotly_dash/util.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
2424
'''
2525

26+
import uuid
27+
2628
from django.conf import settings
29+
from django.core.cache import cache
2730

2831
def _get_settings():
2932
try:
@@ -57,3 +60,38 @@ def http_poke_endpoint_enabled():
5760
def cache_timeout_initial_arguments():
5861
'Return cache timeout, in seconds, for initial arguments'
5962
return _get_settings().get('cache_timeout_initial_arguments', 60)
63+
64+
def initial_argument_location():
65+
'Return True if cache to be used for setting and getting initial arguments, or False for a session'
66+
67+
setget_location = _get_settings().get('cache_arguments', True)
68+
69+
return setget_location
70+
71+
def store_initial_arguments(request, initial_arguments=None):
72+
'Store initial arguments, if any, and return a cache identifier'
73+
74+
if initial_arguments is None:
75+
return None
76+
77+
# Generate a cache id
78+
cache_id = "dpd-initial-args-%s" % str(uuid.uuid4()).replace('-', '')
79+
80+
# Store args in json form in cache
81+
if initial_argument_location():
82+
cache.set(cache_id, initial_arguments, cache_timeout_initial_arguments())
83+
else:
84+
request.session[cache_id] = initial_arguments
85+
86+
return cache_id
87+
88+
def get_initial_arguments(request, cache_id=None):
89+
'Extract initial arguments for the dash app'
90+
91+
if cache_id is None:
92+
return None
93+
94+
if initial_argument_location():
95+
return cache.get(cache_id)
96+
97+
return request.session[cache_id]

django_plotly_dash/views.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@
2727
import json
2828

2929
from django.http import HttpResponse, HttpResponseRedirect
30-
from django.core.cache import cache
3130

3231
from .models import DashApp
32+
from .util import get_initial_arguments
3333

3434
def routes(*args, **kwargs):
3535
'Return routes'
@@ -52,10 +52,7 @@ def layout(request, ident, stateless=False, cache_id=None, **kwargs):
5252
view_func = app.locate_endpoint_function('dash-layout')
5353
resp = view_func()
5454

55-
if cache_id:
56-
initial_arguments = cache.get(cache_id)
57-
else:
58-
initial_arguments = None
55+
initial_arguments = get_initial_arguments(request, cache_id)
5956

6057
response_data, mimetype = app.augment_initial_layout(resp, initial_arguments)
6158
return HttpResponse(response_data,

docs/configuration.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ below.
2727
2828
# Name of view wrapping function
2929
"view_decorator": None,
30+
31+
# Flag to control location of initial argument storage
32+
"cache_arguments": True,
3033
}
3134
3235
Defaults are inserted for missing values. It is also permissible to not have any ``PLOTLY_DASH`` entry in
@@ -72,4 +75,12 @@ To restrict all access to logged-in users, use the ``login_required`` wrapper:
7275
7376
More information can be found in the :ref:`view decoration <access_control>` section.
7477

78+
.. _cache_arguments:
79+
80+
Initial arguments
81+
-----------------
7582

83+
Initial arguments are stored within the server between the specification of an app in a template tag and the invocation of the
84+
view functions for the app. This storage is transient and can be efficiently performed using Django's caching framework. In some
85+
situations, however, a suitably configured cache is not available. For this use case, setting the ``cache_arguments`` flag to ``False`` will
86+
cause initial arguments to be placed inside the Django session.

0 commit comments

Comments
 (0)