[streamlit] 튜토리얼 > 동적 탐색 메뉴 만들기
[출처] https://docs.streamlit.io/develop/tutorials/multipage/dynamic-navigation
1. Intro
st.navigation을 사용하면 동적 탐색 메뉴를 쉽게 만들 수 있습니다. 재실행할 때마다 st.navigation으로 전달되는 페이지 집합을 변경하면 탐색 메뉴가 그에 맞게 변경됩니다. 이 기능은 사용자 지정 역할 기반 탐색 메뉴를 만들 때 편리한 기능입니다.
이 튜토리얼에서는 Streamlit 버전 1.36.0에 도입된 st.navigation 및 st.Page를 사용합니다. pages/ 디렉토리 및 st.page_link를 사용하는 과거의 방법은 st.page_link를 사용하여 사용자 정의 탐색 메뉴 만들기를 참조하세요.
Applied concepts
- st.navigation 및 st.Page를 사용하여 다중 페이지 앱을 정의합니다.
- 동적인 역할 기반 탐색 메뉴를 만듭니다.
Prerequisites
- 파이썬 환경에는 다음이 설치되어 있어야 합니다: streamlit>=1.36.0
- your-repository 라는 깨끗한 작업 디렉터리가 있어야 합니다.
- st.navigation 및 st.Page에 대한 기본적인 이해가 있어야 합니다.
Summary
이 예제에서는 현재 사용자의 역할에 따라 달라지는 다중 페이지 앱의 동적 탐색 메뉴를 구축하겠습니다. 예제를 단순화하기 위해 사용자 이름 및 자격 증명 사용을 추상화하겠습니다. 대신 선택 상자를 사용하여 사용자가 역할을 선택하고 로그인할 수 있도록 합니다.
엔트리포인트 파일인 streamlit_app.py는 사용자 인증을 처리합니다. 다른 페이지는 계정 관리(settings.py)와 세 가지 역할에 연결된 특정 페이지를 나타내는 스텁입니다: 요청자, 응답자, 관리자입니다. 요청자는 계정 및 요청 페이지에 액세스할 수 있습니다. 응답자는 계정에 액세스하여 페이지에 응답할 수 있습니다. 관리자는 모든 페이지에 액세스할 수 있습니다.
구축할 내용을 살펴보세요:
Directory structure:
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()
2. Build the example
2.1. Initialize your app
1. your_repository에서 streamlit_app.py라는 파일을 생성합니다.
2. 터미널에서 디렉터리를 your_repository로 변경하고 앱을 시작합니다.
streamlit run streamlit_app.py
아직 코드를 추가해야 하므로 앱이 비어 있습니다.
3. streamlit_app.py에 다음을 작성합니다:
import streamlit as st
4. streamlit_app.py 파일을 저장하고 실행 중인 앱을 확인합니다.
5. '항상 다시 실행'을 클릭하거나 실행 중인 앱에서 'A' 키를 누르세요.
streamlit_app.py에 변경 사항을 저장하면 실행 중인 미리보기가 자동으로 업데이트됩니다. 미리보기는 여전히 비어 있습니다. 코드로 돌아갑니다.
2.2. Add your page and image files
1. your_repositoy에서 settings.py라는 파일을 만듭니다.
2. 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에 저장하는 인증 방법을 만들 것입니다. 사용자가 로그인할 때까지 이 페이지에 대한 액세스를 차단할 것이므로 이 페이지에 대한 세션 상태의 "role" 키를 초기화할 필요가 없습니다.
3. 다음 6개 페이지에 대해 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"You are logged in as {st.session_state.role}.")
4. 리포지토리에 이미지 하위 디렉터리를 만들고 다음 두 파일을 추가합니다:
이제 앱을 빌드하는 데 필요한 모든 파일이 준비되었습니다.
2.3. Initialize global values
1. streamlit_app.py로 돌아가서 세션 상태의 "role"을 초기화합니다.
if "role" not in st.session_state:
st.session_state.role = None
이 값을 사용하여 앱에 대한 액세스를 게이트키핑합니다. 이 값은 현재 인증된 사용자의 역할을 나타냅니다.
2. 사용 가능한 역할을 정의합니다.
ROLES = [None, "Requester", "Responder", "Admin"]
None은 인증되지 않은 사용자에 해당하는 값이므로 역할에 포함되지 않습니다.
2.4. Define your user authentication pages
st.navigation을 사용하면 Python 함수에서 페이지를 정의할 수 있습니다. 여기서는 파이썬 함수에서 로그인 및 로그아웃 페이지를 정의합니다.
1. 로그인 페이지(기능 정의)를 시작합니다.
def login():
2. 페이지의 헤더를 추가합니다.
st.header("Log in")
3. 사용자가 역할을 선택할 수 있는 선택 상자를 만듭니다.
role = st.selectbox("Choose your role", ROLES)
4. 사용자 역할을 세션 상태에 커밋하는 버튼을 추가합니다.
if st.button("Log in"):
st.session_state.role = role
st.rerun()
이것은 인증 워크플로우의 추상화입니다. 사용자가 버튼을 클릭하면 스트림릿은 역할을 세션 상태에 저장하고 앱을 다시 실행합니다. 이후 단계에서는 st.session_state.role의 값이 변경될 때 사용자를 역할의 기본 페이지로 안내하는 로직을 추가합니다. 이것으로 로그인 페이지 함수가 완성되었습니다.
5. 로그아웃 페이지(기능 정의)를 시작합니다.
def logout():
6. 즉시 역할을 None으로 설정하고 앱을 다시 실행합니다.
st.session_state.role = None
st.rerun()
로그아웃 페이지 기능은 세션 상태를 즉시 업데이트하고 재실행하므로 사용자는 이 페이지를 볼 수 없습니다. 이 페이지는 순식간에 실행되며 재실행 시 앱은 사용자를 로그인 페이지로 전송합니다. 따라서 페이지에 추가 요소가 렌더링되지 않습니다. 원하는 경우 이 페이지에 로그인 페이지와 유사한 버튼을 포함하도록 변경할 수 있습니다. 버튼을 사용하면 사용자가 실제로 로그아웃할 의사가 있는지 확인할 수 있습니다.
2.5. Define all your pages
1. 편의를 위해 st.session_state.role을 변수에 저장하세요.
role = st.session_state.role
2. 계정 페이지를 정의합니다.
logout_page = st.Page(logout, title="Log out", icon=":material/logout:")
settings = st.Page("settings.py", title="Settings", icon=":material/settings:")
이렇게 하면 각 페이지에 멋진 제목과 아이콘을 지정하여 탐색 메뉴를 깔끔하고 깔끔하게 만들 수 있습니다.
3. 요청 페이지를 정의합니다.
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에서 기본 페이지를 수동으로 선언하지 않으면 첫 번째 페이지가 자동으로 기본 페이지가 됩니다. 메뉴의 첫 페이지는 메뉴의 '계정' 섹션에 있는 '로그아웃'이 됩니다. 따라서 각 사용자가 기본적으로 어떤 페이지로 이동해야 하는지 스트림릿에 알려주어야 합니다.
이 코드는 역할이 "Requester" 인 경우 기본값을 default=True로 설정하고 그렇지 않은 경우 기본값을 False로 동적으로 설정합니다.(defualt 설정을 안해주면 아무 페이지도 안보임)
4. 남은 페이지를 정의합니다.
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:")
5. 요청 페이지와 마찬가지로 다른 역할의 기본 페이지에도 기본 매개변수가 설정됩니다.
account_pages = [logout_page, settings]
request_pages = [request_1, request_2]
respond_pages = [respond_1, respond_2]
admin_pages = [admin_1, admin_2]
로그인한 사용자가 사용할 수 있는 모든 페이지입니다.
2.6. Define your common elements and navigation
1. 모든 페이지에 표시할 제목을 추가합니다.
st.title("Request manager")
엔트리포인트 파일에서 제목 명령을 호출하기 때문에 이 제목은 모든 페이지에 표시됩니다. 엔트리포인트 파일에서 생성된 요소는 모든 페이지에 공통 요소의 프레임을 만듭니다.
2. 앱에 로고를 추가하세요.
st.logo("images/horizontal_blue.png", icon_image="images/icon_blue.png")
다시 한 번 말하지만, 엔트리포인트 파일에서 이 명령을 호출하기 때문에 각 페이지 내에서 이 명령을 호출할 필요는 없습니다.
3. 페이지 목록 딕셔너리를 초기화합니다.
page_dict = {}
다음 단계에서는 사용자의 역할을 확인하고 사용자가 액세스할 수 있는 페이지를 딕셔너리에 추가합니다. st.navigation이 페이지 목록의 딕셔너리를 받으면 페이지 그룹과 섹션 헤더가 포함된 탐색 메뉴를 만듭니다.
4. 사용자의 역할을 확인하여 허용된 페이지의 딕셔너리를 구축합니다.
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
5. 사용자가 페이지에 액세스할 수 있는지 확인하고 허용된 경우 계정 페이지를 추가합니다.
if len(page_dict) > 0:
pg = st.navigation({"Account": account_pages} | page_dict)
page_dict가 비어 있지 않으면 사용자가 로그인한 것입니다. 연산자는 두 사전을 병합하여 계정 페이지를 처음에 추가합니다.
6. 사용자가 로그인하지 않은 경우 로그인 페이지로 폴백합니다.
else:
pg = st.navigation([st.Page(login)])
7. st.navigation이 반환한 페이지를 실행합니다.
pg.run()
8. streamlit_app.py 파일을 저장하고 앱을 확인하세요!
로그인, 페이지 전환, 로그아웃을 시도해 보세요. 다른 역할로 다시 시도해 보세요.
(1) None으로 로그인
- None으로 로그인하면 사이드바에 아무 페이지도 나오지 않음
(2) Requester로 로그인
(3) Responder로 로그인
(4) Admin으로 로그인