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 配置选项结合使用时,您可以在应用程序中构建时尚、动态的导航。
Prerequisites
在你的开发环境中创建一个新的工作目录。我们将这个目录称为your-repository。
Summary
在这个例子中,我们将为一个多页面应用构建一个动态导航菜单,该菜单依赖于当前用户的角色。为了简化示例,我们抽象了用户名和凭证的使用。相反,我们将在应用的主页上使用一个选择框来切换角色。Session State 将在页面之间传递这个选择。应用将有一个主页面(app.py),作为抽象的登录页面。根据当前角色,将有三个额外的页面被隐藏或可访问。文件结构如下:
your-repository/
├── .streamlit/
│ └── config.toml
├── pages/
│ ├── admin.py
│ ├── super-admin.py
│ └── user.py
├── menu.py
└── app.py
这是我们即将构建的内容:
Build the example
Hide the default sidebar navigation
在创建自定义导航菜单时,您需要使用client.showSidebarNavigation隐藏默认的侧边栏导航。将以下.streamlit/config.toml文件添加到您的工作目录中:
[client]
showSidebarNavigation = false
Create a menu function
你可以为不同的页面编写不同的菜单逻辑,或者你可以创建一个单一的菜单函数在多个页面上调用。在这个例子中,我们将在所有页面上使用相同的菜单逻辑,包括当用户未登录时重定向到主页。我们将构建一些辅助函数来实现这一点。
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。
提示
如果你想在页面标签中包含表情符号,你可以使用icon参数。不需要在文件名或label参数中包含表情符号。
Create the main file of your app
主要的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!
Add other pages to your app
添加以下 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")按钮,这样你就可以在选择“用户”角色后导航到管理页面。😉
还有问题吗?
我们的 论坛 充满了有用的信息和Streamlit专家。