Is there a way to have multiple pages like flask?

Hi, I just finished streamlit tutorial and I was wondering if there is a way to have a multiple page like flask.

Maybe code would look like this

from flask import Flask
import streamlit as st

app = Flask(__name__)

@app.route('/')
def home():
    return 'this is home'

@app.route('/page1')
def page1():
    st.button('this is page1')

if __name__ == '__main__':
    app.run()

I’ve tried making multi page after watching data professors video on youtube, but it’s not quite what I’m looking for.

1 Like

Hi 2asy,

you can try my Multipage framework for this
streamlit-multipage/MultiPage.py at main · akshanshkmr/streamlit-multipage (github.com)

from MultiPage import MultiPage
from apps import first_app, second_app, third_app

app = MultiPage()
app.add_app('App1',first_app.app)
app.add_app('App2',second_app.app)
app.add_app('App3',third_app.app)
app.run()

This should fulfill your usecase

Thanks

1 Like

you can use the streamlit_pages package directly

2 Likes

Or you could use the most mature multi-page framework for Streamlit, Hydralit, with animated menu, extensive code examples and the ability to customise your session state and even use login and security.

@Probability
Super cool package Hydralit. Thanks for sharing in the forum.

Does it support query params?

Yes, it completely supports query parameters. In fact, if you want to use the secure internal navigation as well as query parameter navigation at the same time, 3 lines of code in the parent (see the comment section USE QUERY PARAMETER NAVIGATION below) and 1 line in each of the child applications is all that is required. For example, the Hydralit example application can use query parameter navigation as well as internal by adding the 3 lines shown in the comments and the 1 line shown, at the top of the run method of each child app.

Using query parameters is not recommended if you are creating a secure app, as you are exposing the ability to by-pass any security checks in place, however Hydralit can use this method if you want, it won’t work when using a secure app, as being able to jump straight to a page within a secure app without authentication defeats the purpose of the security.

Using this, you could then bookmark any child app and jump to it directly, for example the parent app code for the Hydralit example with the 3 lines added that will allow query parameter navigation.

You can see the full code and a live running example of the original source below here.

from hydralit import HydraApp
import streamlit as st
import apps


if __name__ == '__main__':
    #this is the host application, we add children to it and that's it!
    app = HydraApp(title='Hydralit Data Explorer',favicon="🐙",nav_horizontal=True,hide_streamlit_markers=True)
  
   # The Home app, this is the default redirect if no target app is specified.
    app.add_app("Home", icon="🏠", app=apps.HomeApp(title='Home'),is_home=True)

    #add all your child apps here
    app.add_app("Cheat Sheet", icon="📚", app=apps.CheatApp(title="Cheat Sheet"))
    app.add_app("Sequency Denoising",icon="🔊", app=apps.WalshApp(title="Sequency Denoising"))
    app.add_app("Sequency (Secure)",icon="🔊🔒", app=apps.WalshAppSecure(title="Sequency (Secure)"))
    app.add_app("Solar Mach", icon="🛰️", app=apps.SolarMach(title="Solar Mach"))
    app.add_app("Spacy NLP", icon="⌨️", app=apps.SpacyNLP(title="Spacy NLP"))
    app.add_app("Uber Pickups", icon="🚖", app=apps.UberNYC(title="Uber Pickups"))
    app.add_app("Solar Mach", icon="🛰️", app=apps.SolarMach(title="Solar Mach"))

    #we want to have secure access for this HydraApp, so we provide a login application
    #optional logout label, can be blank for something nicer!
    #app.add_app("Login", apps.LoginApp(title='Login'),is_login=True) 

    # If the menu is cluttered, just rearrange it into sections!
    # completely optional, but if you have too many entries, you can make it nicer by using accordian menus
    complex_nav = {
        'Home': ['Home'],
        'Intro 🏆': ['Cheat Sheet',"Solar Mach"],
        'Hotstepper 🔥': ["Sequency Denoising","Sequency (Secure)"],
        'Models 🧩': ["Spacy NLP","Uber Pickups"],
    }

    # ----------USE QUERY PARAMETER NAVIGATION----------------------------------------
    # If we want to use query parameters to control the navigation, 
    # for example we could bookmark a specific app and jump straight to it.
    # --------------------------------------------------------------------------------
    query_params = st.experimental_get_query_params()
    if 'selected' in query_params:
      app.session_state.selected_app = (query_params['selected'])[0]
    # --------------------------------------------------------------------------------
    # At the top of the run() method of each child app, just 
    # add this one line and it will also update the query parameter regardless of the source of navigation
    # st.experimental_set_query_params(selected=self.title)

    #create a wrapper class
    # class MySmallApp(HydraHeadApp):

    # #wrap all your code in this method and you should be done
    #     def run(self):
    #         #--------now using query parameter nav as well as internal navigation

              st.experimental_set_query_params(selected=self.title)

    #         #-------------------existing untouched code------------------------------------------
    #         st.title('Small Application with a table and chart.')

    #         st.markdown("### Plot")
    #         df = create_table()

    #         st.line_chart(df)
    # --------------------------------------------------------------------------------

    # Run the Hydra
    app.run(complex_nav)
1 Like

Yes, you can use a text file to hold the page name as and when the link of each of them is clicked and allow streamlit to read from the text file. That way you can be switching between pages.

@probability This is not entirely true. If you decorate your page entry point functions with security checks then you can support security even with bookmarks. Look at the simple security framework I released, as you should be able to integrate it into Hydralit very easily? A security check function decorator is available out-of-the-box.

Arvindra

1 Like

I completely agree with @asehmi

I also use nginx auth in the entry point of my app with query params,
No matter which app the user visits, he’ll first have to go through the auth checks.

@asehmi sure, if you want to put authentication checking in every single child app. I built Hydralit to make it easy to have gateway style access to all the child apps in one go, the auth checking occurs in one place instead of every single app. If you have a multi-app frame work that uses query parameters, @akshanshkmr , I’m sure you second any process that uses query parameters. That’s great if we were living in the early 2000’s, but SPA patterns and internally managed states are the modern way of doing it, but go for whatever works. implement your solution however you want. I built Hydralit to follow the philosophy of Streamlit, make it easy and just work with minimal code for people who aren’t web developers. If you are a web developer and know all about query parameters and the best way to implement rock hard security with perm links and cookies, etc. knock yourself out. I’ll be making one more primary update to the Hydralit package and related projects, then I will be happy to step back from this community of experts and you can use @akshanshkmr framework or wait for Streamlit to implement their solution or something else entirely, until then do security, multi-apps and the rest however you want. My comments where in response to query parameters and the Hydralit framework, so we’ll agree to not entirely agree.

@probability - I think the single entry point authenticated gateway approach and finer-grained authentication approach can coexist quite happily, and still be easy to implement for Streamlit, i.e. non-web, app developers. I personally would encourage you to continue providing your excellent and creative solutions for the benefit of this community. There’s room for everyone to be innovative and add value.

Thanks,
Arvindra

1 Like

So does this Hydralit framework (or other multipage methods for Streamlit) support overall cacheing of the pages that make up. the app?
I.e if I move off a page within my app and come back again will my cached objects still be cached?

Currently I have not seen anything that can do this. The page always gets reset.

If you don’t want to use Hydralit you can always do something like this.
app.py

import streamlit as st

from src import first_page, second_page

state = st.session_state

first_page_title= "first_page"
second_page_title = "second_page"
page_titles = [first_page_title, second_page_title]

def page_change():
    st.experimental_set_query_params(page=state.page_select)


# on first run, set page index to page in query params
# if that doesn't exist, set it to 0 and set the query params to the first page
page_index = 0
if "first_run" not in state:
    state.first_run = True
    if "page" in st.experimental_get_query_params():
        page_index = page_titles.index(st.experimental_get_query_params()["page"][0])
    st.experimental_set_query_params(page=page_titles[page_index])

# Page Selector
# value isn't saved since it's tracked in the query params.
st.sidebar.selectbox("Navigation", page_titles, key="page_select", on_change=page_change, index=page_index)

# get the page from the query params
page = st.experimental_get_query_params()["page"][0]

# load the selected page
if page == first_page_title:
    first_page.run()
elif page == second_page_title:
    second_page.run()

To track seperate states for each page you can just use page specific state dictionaries like so.

first_page.py

state_name = "first_page_state"
# initialize the page specific state
if state_name not in st.session_state:
    st.session_state[state_name] = {}
# assign it to a variable so you don't have to worry about referencing the right state
# further in this code
state = st.session_state[state_name]

# then reference values with dictionary notation
state['value'] = ....
1 Like

A related post on multiple pages:

thanks - some interesting ideas here

In one of my ‘multi-page related threads’ on these forums, Randy (@randyzwitch) said that Streamlit is working on a supported solution to integrate multi-paging into Streamlit. Good news!