Create a dynamic navigation menu
st.navigation 使得构建动态导航菜单变得容易。您可以在每次重新运行时更改传递给 st.navigation 的页面集合,从而更改导航菜单以匹配。这是一个方便的功能,用于创建自定义的、基于角色的导航菜单。
本教程使用st.navigation和st.Page,这两个功能是在Streamlit版本1.36.0中引入的。对于使用pages/目录和st.page_link的旧版解决方案,请参阅使用st.page_link构建自定义导航菜单。
Applied concepts
- 使用
st.navigation和st.Page来定义一个多页面应用。 - 创建一个动态的、基于角色的导航菜单。
Prerequisites
-
您的Python环境中必须安装以下内容:
streamlit>=1.36.0 -
你应该有一个干净的工作目录,名为
your-repository。 -
你应该对
st.navigation和st.Page有一个基本的了解。
Summary
在这个例子中,我们将为多页面应用构建一个动态导航菜单,该菜单依赖于当前用户的角色。为了简化示例,您将抽象化用户名和凭据的使用。相反,您将使用一个选择框让用户选择角色并登录。
入口文件 streamlit_app.py 将处理用户认证。其他页面将是表示账户管理 (settings.py) 和与三个角色相关的特定页面的存根:请求者、响应者和管理员。请求者可以访问账户和请求页面。响应者可以访问账户和响应页面。管理员可以访问所有页面。
这是我们即将构建的内容:
目录结构:
your-repository/
├── admin
│ ├── admin_1.py
│ └── admin_2.py
├── images
│ ├── horizontal_blue.png
│ └── icon_blue.png
├── request
│ ├── request_1.py
│ └── request_2.py
├── respond
│ ├── respond_1.py
│ └── respond_2.py
├── settings.py
└── streamlit_app.py
streamlit_app.py:
import streamlit as st
if "role" not in st.session_state:
st.session_state.role = None
ROLES = [None, "Requester", "Responder", "Admin"]
def login():
st.header("Log in")
role = st.selectbox("Choose your role", ROLES)
if st.button("Log in"):
st.session_state.role = role
st.rerun()
def logout():
st.session_state.role = None
st.rerun()
role = st.session_state.role
logout_page = st.Page(logout, title="Log out", icon=":material/logout:")
settings = st.Page("settings.py", title="Settings", icon=":material/settings:")
request_1 = st.Page(
"request/request_1.py",
title="Request 1",
icon=":material/help:",
default=(role == "Requester"),
)
request_2 = st.Page(
"request/request_2.py", title="Request 2", icon=":material/bug_report:"
)
respond_1 = st.Page(
"respond/respond_1.py",
title="Respond 1",
icon=":material/healing:",
default=(role == "Responder"),
)
respond_2 = st.Page(
"respond/respond_2.py", title="Respond 2", icon=":material/handyman:"
)
admin_1 = st.Page(
"admin/admin_1.py",
title="Admin 1",
icon=":material/person_add:",
default=(role == "Admin"),
)
admin_2 = st.Page("admin/admin_2.py", title="Admin 2", icon=":material/security:")
account_pages = [logout_page, settings]
request_pages = [request_1, request_2]
respond_pages = [respond_1, respond_2]
admin_pages = [admin_1, admin_2]
st.title("Request manager")
st.logo("images/horizontal_blue.png", icon_image="images/icon_blue.png")
page_dict = {}
if st.session_state.role in ["Requester", "Admin"]:
page_dict["Request"] = request_pages
if st.session_state.role in ["Responder", "Admin"]:
page_dict["Respond"] = respond_pages
if st.session_state.role == "Admin":
page_dict["Admin"] = admin_pages
if len(page_dict) > 0:
pg = st.navigation({"Account": account_pages} | page_dict)
else:
pg = st.navigation([st.Page(login)])
pg.run()
Build the example
Initialize your app
-
在
your_repository中,创建一个名为streamlit_app.py的文件。 -
在终端中,将目录更改为
your_repository并启动您的应用程序。streamlit run streamlit_app.py由于您仍然需要添加代码,您的应用程序将是空白的。
-
在
streamlit_app.py中,编写以下内容:import streamlit as st -
保存您的
streamlit_app.py文件并查看正在运行的应用程序。 -
点击“始终重新运行”或在运行的应用中按下“A”键。
当您保存对
streamlit_app.py的更改时,您的运行预览将自动更新。您的预览仍将为空。返回您的代码。
Add your page and image files
-
在
your_repositoy中,创建一个名为settings.py的文件。 -
在
settings.py中添加以下存根。import streamlit as st st.header("Settings") st.write(f"You are logged in as {st.session_state.role}.")在后续步骤中,您将创建一个身份验证方法,将当前用户的角色保存到
st.session_state.role。由于您将阻止访问此页面,直到用户登录为止,因此您不需要为此页面初始化Session State中的"role"键。 -
通过更改以下六个页面的
st.header值来创建类似的存根:your-repository/ ├── admin │ ├── admin_1.py │ └── admin_2.py ├── request │ ├── request_1.py │ └── request_2.py └── respond ├── respond_1.py └── respond_2.py例如,
admin/admin_1.py应该是以下内容:import streamlit as st st.header("Admin 1") st.write(f"您以 {st.session_state.role} 的身份登录。") -
在
your-repository中创建一个images子目录,并添加以下两个文件:你现在拥有了构建应用程序所需的所有文件。
Initialize global values
-
返回到
streamlit_app.py并在 Session State 中初始化"role"。if "role" not in st.session_state: st.session_state.role = None您将使用此值来控制对应用程序的访问。这表示当前经过身份验证的用户的角色。
-
定义可用的角色。
ROLES = [None, "Requester", "Responder", "Admin"]None被包含为一个角色,因为这是对应于未认证用户的值。
Define your user authentication pages
st.navigation 允许你从Python函数定义页面。在这里,你将从Python函数定义登录和注销页面。
-
开始你的登录页面(函数定义)。
def login(): -
为页面添加一个标题。
st.header("Log in") -
创建一个选择框供用户选择角色。
role = st.selectbox("Choose your role", ROLES) -
添加一个按钮以将用户角色提交到会话状态。
if st.button("Log in"): st.session_state.role = role st.rerun()这是身份验证工作流程的抽象。当用户点击按钮时,Streamlit 将角色保存到会话状态并重新运行应用程序。在后续步骤中,您将添加逻辑,以在
st.session_state.role中的值更改时将用户定向到角色的默认页面。这将完成您的登录页面功能。 -
开始你的注销页面(函数定义)。
def logout(): -
立即将角色设置为
None并重新运行应用程序。st.session_state.role = None st.rerun()由于注销页面功能会立即更新会话状态并重新运行,用户将永远不会看到此页面。页面将在几分之一秒内执行,并在重新运行时将用户发送到登录页面。因此,页面上不会呈现其他元素。如果需要,您可以将此页面更改为包含一个按钮,类似于登录页面。按钮将允许用户确认他们确实打算注销。
Define all your pages
-
为了方便,将
st.session_state.role保存到一个变量中。role = st.session_state.role -
定义您的账户页面。
logout_page = st.Page(logout, title="Log out", icon=":material/logout:") settings = st.Page("settings.py", title="Settings", icon=":material/settings:")这为每个页面提供了一个漂亮的标题和图标,使您的导航菜单看起来整洁干净。
-
定义您的请求页面。
request_1 = st.Page( "request/request_1.py", title="Request 1", icon=":material/help:", default=(role == "Requester"), ) request_2 = st.Page( "request/request_2.py", title="Request 2", icon=":material/bug_report:" )如果您没有在
st.navigation中手动声明默认页面,那么第一个页面将自动成为默认页面。菜单中的第一个页面将是“注销”,位于菜单的“账户”部分。因此,您需要告诉Streamlit每个用户默认应该被定向到哪个页面。此代码在角色为“Requester”时动态设置
default=True,否则设置为False。 -
定义您的剩余页面。
respond_1 = st.Page( "respond/respond_1.py", title="Respond 1", icon=":material/healing:", default=(role == "Responder"), ) respond_2 = st.Page( "respond/respond_2.py", title="Respond 2", icon=":material/handyman:" ) admin_1 = st.Page( "admin/admin_1.py", title="Admin 1", icon=":material/person_add:", default=(role == "Admin"), ) admin_2 = st.Page("admin/admin_2.py", title="Admin 2", icon=":material/security:")与请求页面类似,
default参数设置为其他角色的默认页面。 -
将您的页面分组为方便的列表。
account_pages = [logout_page, settings] request_pages = [request_1, request_2] respond_pages = [respond_1, respond_2] admin_pages = [admin_1, admin_2]这些是所有登录用户可用的页面。
Define your common elements and navigation
-
在所有页面上添加一个标题。
st.title("Request manager")由于你在入口点文件中调用了标题命令,这个标题将在所有页面上可见。在入口点文件中创建的元素会在所有页面周围创建一个公共元素的框架。
-
为您的应用程序添加一个标志。
st.logo("images/horizontal_blue.png", icon_image="images/icon_blue.png")再次强调,由于您在入口点文件中调用此命令,因此不需要在每个页面中再次调用它。
-
初始化页面列表的字典。
page_dict = {}在下一步中,您将检查用户的角色,并将用户允许访问的页面添加到字典中。当
st.navigation接收到页面列表的字典时,它会创建一个带有页面组和部分标题的导航菜单。 -
通过检查用户的角色来构建允许页面的字典。
if st.session_state.role in ["Requester", "Admin"]: page_dict["Request"] = request_pages if st.session_state.role in ["Responder", "Admin"]: page_dict["Respond"] = respond_pages if st.session_state.role == "Admin": page_dict["Admin"] = admin_pages -
检查用户是否被允许访问任何页面,如果是,则添加账户页面。
if len(page_dict) > 0: pg = st.navigation({"Account": account_pages} | page_dict)如果
page_dict不为空,则用户已登录。|操作符合并两个字典,将账户页面添加到开头。 -
如果用户未登录,则回退到登录页面。
else: pg = st.navigation([st.Page(login)]) -
执行由
st.navigation返回的页面。pg.run() -
保存您的
streamlit_app.py文件并查看您的应用程序!尝试登录、切换页面和注销。使用不同的角色再次尝试。
还有问题吗?
我们的 论坛 充满了有用的信息和Streamlit专家。