Setting/Getting query_params in st.Page's url_path?

I am creating a local streamlit app using versions 1.40.1. It is a multipage app using st.Navigation. In the st.Navigation I have multiple st.Page. I am trying to programmatically generate pages in the navigation that all link to the same Python file. Further, I set the url_path of the pages to include a query parameter:

def main():
    # Initialize the app
    st.set_page_config(page_title='Perfin', page_icon='', layout='wide')
    initialize_session_state()

    # General pages
    home = st.Page('interface/home.py', title='Home', icon='', default=True)

    # Create account pages with URLs that include query parameters
    account_pages = [
        st.Page(
            'interface/accounts.py', 
            title=account.account_name(),
            icon='',
            url_path=f'/accounts?id={account.id}'
        )
        for account in st.session_state.manager.accounts
    ]

    # Speciality pages
    loans = st.Page('interface/loans.py', title='Loans', icon='')

    # Navigation
    pg = st.navigation({
        'General': [home],
        'Accounts': account_pages,
        'Loans': [loans]
    })

    pg.run()

Then on the linked page I attempt to get the query parameter:

def main():
    # Get the account ID from query parameters
    print(f'Query params: {st.query_params}')
    account_id = st.query_params.get('id', [None])[0]
    account = manager.find_account(account_id)

So that I can “do things” on the page based on the query parameter. Though, I find that st.query_params is always an empty dictionary.

I am fairly certain that to add key-value pairs into st.query_params they need to be set explicitly and that’s why it is not working. Am I correct in that? Or is my setup incorrect?


With respect to what I am trying to accomplish, is there some other way I could programmatically generate an amount N of links to the same Python page and pass a simple value to that page so it knows what to do?

I found a partial solution to the issue by creating a callable that updates the session state prior to loading the page:

def main():
    # Initialize the app
    st.set_page_config(page_title='Perfin', page_icon='', layout='wide')
    initialize_session_state()

    # General pages
    home = st.Page('interface/home.py', title='Home', icon='', default=True)

    # A callable to create account pages. 
    # It sets session state to the account ID then calls the accounts page.
    def create_account_page(account):
        def page_loader():
            st.session_state.selected_account_id = account.id
            # Import and run the accounts page
            import interface.accounts
            interface.accounts.main()
            return interface.accounts

        return st.Page(
            page_loader,
            title=account.account_name(),
            icon='',
            url_path=f'/accounts?id={account.id}'  # Just to make the URL unique
        )

    # Programmatically create account pages for each account
    account_pages = [
        create_account_page(account)
        for account in st.session_state.manager.accounts
    ]

    # Speciality pages
    loans = st.Page('interface/loans.py', title='Loans', icon='')

    # Navigation
    pg = st.navigation({
        'General': [home],
        'Accounts': account_pages,
        'Loans': [loans]
    })

    pg.run()

But I would still prefer to use query_params and not a slightly crackpot workaround.