Independent cache for each user session

Hi,

Is there any example where I can store independent cache for each user session?

I want to locally store some objects so that when user refreshes the browser those unique settings load without having to ask the user for inputs again.

Hi @jitz

Great question. My understanding is that the scope of a user session ends when the user refreshes or reloads. So I read this as you are asking about storing user settings.

User Session Settings

Any variable defined in the .py or .ipynb file you panel serve is saved and available for the user session. It gone when the session ends, i.e. when the user closes the browser or reloads the page.

User Settings

Local Storage in Browser

In javascript you can save to local storage in the users browser. Panel has no mechanism to store to local storage, but if I can build one using ReactiveHTML I will add it as an example below.

Storage on Server

If you somehow can get an unique id key representing your user, you can store the information value in pn.state.cache via pn.state.cache[key]=value.

One way to get a unique id is to generate one and store it in the Local Storage or as a cookie. Then you can either store things to the browsers local storage or on the server side.

1 Like

Here is an example. Its only the beginning of an implementation. The challenge is that the localstorage is not available before the page has loaded.

import uuid
import panel as pn
import param
import uuid

pn.extension(sizing_mode="stretch_width", template="fast")

pn.state.template.param.update(site="Awesome Panel", title="How do I store user settings across reloads?")

class LocalStorage(pn.reactive.ReactiveHTML):
    value = param.Dict(default=None, allow_None=True)
    
    _template = """<div id="local-storage" style="display:hidden"></div>"""

    _scripts = {
        "render": """
if (data.value===null){
    data.value = JSON.parse(window.localStorage.getItem(model.name));
} else {
    window.localStorage.setItem(model.name, JSON.stringify(data.value));
}
""",
    "value": """
if (data.value===null){
    window.localStorage.removeItem(model.name);
} else {
    window.localStorage.setItem(model.name, JSON.stringify(data.value));
}      
"""
    }

    def clear(self, event=None):
        self.value = None

    def update(self, event=None):
        self.param.trigger("value")

# Use name as the "key" for localStorage in the browser
storage = LocalStorage(name="my-value")

clear = pn.widgets.Button(name="Clear Local Storage", button_type="primary")
clear.on_click(storage.clear)

update = pn.widgets.Button(name="Update Local Storage", button_type="primary")
update.on_click(storage.update)

pn.Column(
    """You can use the browsers `Local Storage`. Here is an example.""",
    storage, 
    storage.param.value,
    clear, update
).servable()

def get_local_storage():
    print("local storage", storage.value)

# The local storage value is not available before the app has loaded
pn.state.add_periodic_callback(get_local_storage, period=1000, count=1)


2 Likes

Feel free to open requests on github for getting and setting localstorage as well as cookies.

Definitely worth exploring local storage. In various applications where this was required we usually added an auth provider and then cached data to a database keyed of the authenticated user but that definitely requires a bit more setup.

@Marc Thank you!

I used the storage on server option you recommended. I was able to pickle some of the python object and store them in cache using a unique key. So, now on reload the object would unpickle and load directly on the page.

I also tried to pickle entire panel object but it dint really work. My aim was to be able to reload the state of the panel as it was when the reload happened.

1 Like