dash-labs
dash-labs copied to clipboard
Multi-Page Apps - find a better way to build dash.page_registry
Currently app pages are added to the dash.page_registry when dash.register_page is called. This happens as modules are loaded from the pages/ folder before the app starts. If you try to use dash.page_registry in an app in the pages/ folder, you must use it in a function, otherwise the page registry may not be complete.
Need to find a better way to build dash.page_registry so it's not necessary for people to use a function when trying to use it from within the pages/ folder.
See community discussion here
Description of the workaround here
Here is a potential solution as outlined by @ chriddyp The solution will be a pull request in dash instead of here in dash-labs
Have page_registry values return a function that returns the value. So instead of:
>>> page_registry['historical']['href']
`/the-thing`
it’d be:
>>> page_registry['historical']['href']()
`/the-thing`
meaning:
>>> page_registry['historical']['href']
<function ...>
- Dash users would still use
page_registry['historical']['href']within their code, but the layouts would now contain functions instead of values. Sopages/some_other_page.pycould have:
layout = dcc.Link('Return home',
href=page_registry['home']['href'])
where href would be a function, not the value!
- Then, change Dash’s serializer to handle functions. So when Dash turns Python objects into JSON strings, if it encountered a function it would simply call the function and serialize the value that it got in return
I suspect you’ll be able to do it here: https://github.com/plotly/dash/blob/dev/dash/development/base_component.py#L206
and here: https://github.com/plotly/dash/blob/dev/dash/development/base_component.py#L213
It looks like the above solution may not be ideal:
For example, let's say you would like to create a "topics" sub-menu from within the pages/ folder.
In the proposed solution, the page["path"] is a function. This mean's that you can't create it like below by looping through dash.page_registry because page["path"] has no attribute 'startswith'
for page in dash.page_registry.values()
if page["path"].startswith("/topic")
But if you use the value of the function, then we are back to the same issue. The dash.page_registry is not finished building yet, so the sub-menu will not be complete.
for page in dash.page_registry.values()
if page["path"]().startswith("/topic")
@chriddyp do you have any other comments or suggestions?
For reference, a note I wrote in a DM with @AnnMarieW - the upshot is I don't think we need to worry about this right now but we could consider adding another mechanism in the future if it becomes a big point of friction.
The only solution I see is to move the dash.register_page calls outside the page files so you can ensure they all run first… and that kind of defeats the purpose.
I suppose there would be a way by converting the
dash.register_pagecall into a comment, we could define the format but something like:# register_page # path_template="/a/<id_a>/b/<id_b>" # id="register_pageand then we first read the file and create all the
page_registryentries with that information first, then attach the modules to each entry later. But that seems like an awfully cumbersome & fragile thing to try to teach people, just so they can avoid putting some things in functions occasionally.