Build a custom navigation menu with st.page_link

Streamlit 允许您使用 st.page_link 构建自定义导航菜单和元素。在 Streamlit 1.31.0 版本中引入的 st.page_link 可以链接到您的多页面应用程序中的其他页面或外部站点。当链接到应用程序中的另一个页面时,st.page_link 将显示高亮效果以指示当前页面。当与 client.showSidebarNavigation 配置选项结合使用时,您可以在应用程序中构建时尚、动态的导航。

在你的开发环境中创建一个新的工作目录。我们将这个目录称为your-repository

在这个例子中,我们将为一个多页面应用构建一个动态导航菜单,该菜单依赖于当前用户的角色。为了简化示例,我们抽象了用户名和凭证的使用。相反,我们将在应用的主页上使用一个选择框来切换角色。Session State 将在页面之间传递这个选择。应用将有一个主页面(app.py),作为抽象的登录页面。根据当前角色,将有三个额外的页面被隐藏或可访问。文件结构如下:

your-repository/ ├── .streamlit/ │ └── config.toml ├── pages/ │ ├── admin.py │ ├── super-admin.py │ └── user.py ├── menu.py └── app.py

这是我们即将构建的内容:

在创建自定义导航菜单时,您需要使用client.showSidebarNavigation隐藏默认的侧边栏导航。将以下.streamlit/config.toml文件添加到您的工作目录中:

[client] showSidebarNavigation = false

你可以为不同的页面编写不同的菜单逻辑,或者你可以创建一个单一的菜单函数在多个页面上调用。在这个例子中,我们将在所有页面上使用相同的菜单逻辑,包括当用户未登录时重定向到主页。我们将构建一些辅助函数来实现这一点。

  • menu_with_redirect() 检查用户是否已登录,然后将其重定向到主页或渲染菜单。
  • menu() 将根据用户是否登录调用正确的辅助函数来渲染菜单。
  • authenticated_menu() 将根据认证用户的角色显示菜单。
  • unauthenticated_menu() 将为未认证用户显示一个菜单。

我们将在主页上调用menu(),并在其他页面上调用menu_with_redirect()st.session_state.role将存储当前选择的角色。如果此值不存在或设置为None,则用户未登录。否则,它将保存用户的角色为字符串:"user""admin""super-admin"

将以下menu.py文件添加到您的工作目录中。(我们将在下面更详细地描述这些函数。)

import streamlit as st def authenticated_menu(): # Show a navigation menu for authenticated users st.sidebar.page_link("app.py", label="Switch accounts") st.sidebar.page_link("pages/user.py", label="Your profile") if st.session_state.role in ["admin", "super-admin"]: st.sidebar.page_link("pages/admin.py", label="Manage users") st.sidebar.page_link( "pages/super-admin.py", label="Manage admin access", disabled=st.session_state.role != "super-admin", ) def unauthenticated_menu(): # Show a navigation menu for unauthenticated users st.sidebar.page_link("app.py", label="Log in") def menu(): # Determine if a user is logged in or not, then show the correct # navigation menu if "role" not in st.session_state or st.session_state.role is None: unauthenticated_menu() return authenticated_menu() def menu_with_redirect(): # Redirect users to the main page if not logged in, otherwise continue to # render the navigation menu if "role" not in st.session_state or st.session_state.role is None: st.switch_page("app.py") menu()

让我们更仔细地看一下authenticated_menu()。当调用此函数时,st.session_state.role存在并且具有除None之外的值。

def authenticated_menu(): # Show a navigation menu for authenticated users

导航菜单中的前两页对所有用户都可用。由于我们知道在调用此函数时用户已登录,我们将为主页使用“切换账户”标签。(如果不使用label参数,页面名称将从文件名派生,就像默认侧边栏导航一样。)

st.sidebar.page_link("app.py", label="Switch accounts") st.sidebar.page_link("pages/user.py", label="Your profile")

我们只想向管理员显示接下来的两页。此外,我们选择在管理员用户不是超级管理员时禁用——但不隐藏——超级管理员页面。我们使用disabled参数来实现这一点。(当角色不是"super-admin"时,disabled=True。)

if st.session_state.role in ["admin", "super-admin"]: st.sidebar.page_link("pages/admin.py", label="Manage users") st.sidebar.page_link( "pages/super-admin.py", label="Manage admin access", disabled=st.session_state.role != "super-admin", )

就是这么简单!unauthenticated_menu() 只会显示一个指向应用主页的链接,标签为“登录”。menu() 会简单检查 st.session_state.role 以在两个菜单渲染函数之间切换。最后,menu_with_redirect() 扩展了 menu(),如果用户未登录,则会将他们重定向到 app.py

star

提示

如果你想在页面标签中包含表情符号,你可以使用icon参数。不需要在文件名或label参数中包含表情符号。

主要的app.py文件将充当一个伪登录页面。用户可以从st.selectbox小部件中选择一个角色。一些逻辑将把该角色保存到Session State中,以便在页面之间导航时保留它——即使返回到app.py

将以下app.py文件添加到您的工作目录中:

import streamlit as st from menu import menu # Initialize st.session_state.role to None if "role" not in st.session_state: st.session_state.role = None # Retrieve the role from Session State to initialize the widget st.session_state._role = st.session_state.role def set_role(): # Callback function to save the role selection to Session State st.session_state.role = st.session_state._role # Selectbox to choose role st.selectbox( "Select your role:", [None, "user", "admin", "super-admin"], key="_role", on_change=set_role, ) menu() # Render the dynamic menu!

添加以下 pages/user.py 文件:

import streamlit as st from menu import menu_with_redirect # Redirect to app.py if not logged in, otherwise show the navigation menu menu_with_redirect() st.title("This page is available to all users") st.markdown(f"You are currently logged with the role of {st.session_state.role}.")

如果用户通过URL手动导航到页面,会话状态将重置。因此,如果用户在此示例中尝试访问管理页面,会话状态将被清除,并且他们将作为未认证用户被重定向到主页。然而,在每个受限页面的顶部包含角色检查仍然是一个好习惯。如果角色未被列入白名单,您可以使用st.stop来停止应用程序。

pages/admin.py:

import streamlit as st from menu import menu_with_redirect # Redirect to app.py if not logged in, otherwise show the navigation menu menu_with_redirect() # Verify the user's role if st.session_state.role not in ["admin", "super-admin"]: st.warning("You do not have permission to view this page.") st.stop() st.title("This page is available to all admins") st.markdown(f"You are currently logged with the role of {st.session_state.role}.")

pages/super-admin.py:

import streamlit as st from menu import menu_with_redirect # Redirect to app.py if not logged in, otherwise show the navigation menu menu_with_redirect() # Verify the user's role if st.session_state.role not in ["super-admin"]: st.warning("You do not have permission to view this page.") st.stop() st.title("This page is available to super-admins") st.markdown(f"You are currently logged with the role of {st.session_state.role}.")

如上所述,menu_with_redirect()中的重定向将阻止用户看到管理页面上的警告消息。如果你想看到警告,只需在app.py的底部添加另一个st.page_link("pages/admin.py")按钮,这样你就可以在选择“用户”角色后导航到管理页面。😉

forum

还有问题吗?

我们的 论坛 充满了有用的信息和Streamlit专家。