Reflex를 사용하여 순수 Python 웹 앱 구축


Python에 관해 이야기할 때 우리는 Python을 사용하여 데이터 분석을 수행하거나 기계 학습 모델을 구축하는 것에 대해 종종 생각합니다. 다음과 같은 라이브러리를 사용하여 간단한 프로토타입 외부에서 Python으로 전체 웹 애플리케이션을 만드는 것을 논의하는 것은 덜 일반적입니다. 스트림라이트 또는 타이피.
그러나 ‘라이브러리’는 휘어진 다른 프로그래밍 언어와 경쟁하는 웹 애플리케이션 개발 기능을 제공합니다. 전적으로 Python으로 작성된 이 오픈 소스 라이브러리는 사용자가 소규모 데이터 과학 앱부터 대규모 다중 페이지 웹 사이트에 이르기까지 모든 것을 구축하는 데 도움이 됩니다. 강력한 유연성과 직관적인 Python 코드를 통해 Reflex를 사용하여 필요에 맞게 웹 개발을 쉽게 확장할 수 있습니다.
이 기사에서는 Reflex를 사용하여 순수 Python 웹 애플리케이션을 구축하는 기본 사항을 학습합니다.
Reflex를 사용하여 웹 앱 구축
이 튜토리얼에서는 Reflex를 사용하여 웹 애플리케이션을 구축하기 위한 표준을 검토합니다. 모범 사례에서는 전체 환경을 방해하지 않도록 가상 환경을 사용하는 것이 좋습니다.
이를 염두에 두고 아래 코드를 사용하여 Reflex 라이브러리를 설치하여 Reflex 웹 애플리케이션 개발을 시작하겠습니다.
그런 다음 새 프로젝트를 만들고 새 애플리케이션을 시작하여 Reflex를 테스트합니다. 다음 코드를 사용하되 test_app
폴더 이름을 직접 지정하세요.
mkdir test_app
cd test_app
reflex init
위의 코드는 미리 만들어진 템플릿을 사용하여 프로젝트를 생성할지 여부에 대한 질문을 묻는 메시지를 표시합니다.
이 튜토리얼에서는 빈 Reflex 앱을 선택하면 아래와 같이 생성된 새 프로젝트 구조를 볼 수 있습니다.
Reflex 애플리케이션이 제대로 실행되는지 확인하려면 다음 명령을 실행하세요.
애플리케이션을 제공하는 로컬 URL을 방문하세요. 잘 작동하면 아래 이미지와 같은 내용이 표시됩니다.
이것은 Reflex가 생성한 기본 웹 애플리케이션 스캐폴드입니다. 나중에 좀 더 정교한 것을 만들겠지만 기본적인 것부터 시작하겠습니다.
Reflex 라이브러리에서 웹 애플리케이션을 구축하는 데 사용되는 구성 요소를 이해하는 것부터 시작해 보겠습니다. 먼저, 열어보세요
test_app.py
해당 내용을 다음 코드로 바꿉니다.
import reflex as rx
class State(rx.State):
count: int = 0
def increment(self):
self.count += 1
def decrement(self):
self.count -= 1
def index():
return rx.hstack(
rx.button(
"Decrement",
color_scheme="ruby",
on_click=State.decrement,
),
rx.heading(State.count, font_size="2em"),
rx.button(
"Increment",
color_scheme="grass",
on_click=State.increment,
),
spacing="4",
)
app = rx.App()
app.add_page(index)
그러면 아래와 같은 웹사이트가 표시됩니다.
위의 코드에서 무슨 일이 일어나고 있는지 분석해 보겠습니다.
먼저, 변수를 포함하는 상태를 정의합니다( vars
) 및 함수(라고 함) event handlers
) 애플리케이션의 상태를 변경할 수 있습니다.
예를 들어, 다음과 같은 단일 변수를 정의합니다. count
초기값이 0인 정수를 보유합니다.
class State(rx.State):
count: int = 0
그런 다음 사용자 작업에 응답하여 변수를 수정하는 상태 내의 함수인 이벤트 핸들러가 있습니다. 위의 코드에서는 이벤트 핸들러를 다음과 같이 정의합니다.
def increment(self):
self.count += 1
def decrement(self):
self.count -= 1
다음으로 웹 애플리케이션 UI를 다음과 같이 정의합니다.
def index():
return rx.hstack(
rx.button(
"Decrement",
color_scheme="ruby",
on_click=State.decrement,
),
rx.heading(State.count, font_size="2em"),
rx.button(
"Increment",
color_scheme="grass",
on_click=State.increment,
),
spacing="4",
)
위의 함수는 웹 애플리케이션 인터페이스를 정의하고 다음 구성 요소를 사용하여 UI를 구축합니다.
rx.hstack
: 요소를 수평으로 쌓는 데 사용됩니다.rx.button
: 클릭 시 이벤트를 트리거하는 버튼을 표시하는 데 사용됩니다.rx.heading
: 다양한 크기로 텍스트를 표시하는 데 사용됩니다.
위 코드에서 볼 수 있듯이 제목 구성 요소는 count
상태의 변수이며, 각 버튼을 클릭하면 해당 상태의 기능이 트리거됩니다.
웹 애플리케이션을 구축하는 데 사용할 수 있는 더 많은 구성 요소가 있습니다. Reflex 구성 요소 문서를 참조하세요.
마지막으로 다음 코드를 사용하여 애플리케이션을 정의하고 구성 요소를 기본 경로에 추가합니다.
app = rx.App()
app.add_page(index)
이는 Reflex가 웹 애플리케이션을 구축하는 데 사용하는 중요한 구성 요소에 대한 간단한 설명입니다.
위의 설명을 마치고 Reflex를 사용하여 좀 더 고급 웹 애플리케이션을 구축해 보겠습니다. 아래 예에서는 항목을 채우고 제거할 수 있는 할 일 목록 애플리케이션을 개발합니다.
import uuid
import reflex as rx
from typing import Any, Dict, List
class TodoState(rx.State):
todos: List[Dict[str, Any]] = []
new_text: str = ""
current_filter: str = "all" # Select between "all", "active", "done"
# Derived values (computed from state)
@rx.var
def items_left(self) -> int:
return sum(1 for t in self.todos if not t["done"])
@rx.var
def items_left_label(self) -> str:
return "1 item left" if self.items_left == 1 else f"{self.items_left} items left"
@rx.var
def filtered_todos(self) -> List[Dict[str, Any]]:
if self.current_filter == "active":
return [t for t in self.todos if not t["done"]]
if self.current_filter == "done":
return [t for t in self.todos if t["done"]]
return self.todos
# Events (mutate state)
@rx.event
def set_new_text(self, value: str):
self.new_text = (value or "").strip()
@rx.event
def add_todo(self):
text = (self.new_text or "").strip()
if not text:
return
self.todos.append({"id": str(uuid.uuid4()), "text": text, "done": False})
self.new_text = ""
@rx.event
def toggle(self, todo_id: str):
for t in self.todos:
if t["id"] == todo_id:
t["done"] = not t["done"]
break
@rx.event
def remove(self, todo_id: str):
self.todos = [t for t in self.todos if t["id"] != todo_id]
@rx.event
def clear_completed(self):
self.todos = [t for t in self.todos if not t["done"]]
@rx.event
def set_filter(self, name: str):
if name in {"all", "active", "done"}:
self.current_filter = name
def filter_button(name: str, label: str) -> rx.Component:
return rx.button(
label,
size="2",
variant=rx.cond(TodoState.current_filter == name, "solid", "soft"),
background_color=rx.cond(
TodoState.current_filter == name, "blue.600", "gray.700"
),
color="white",
_hover={"background_color": "blue.500"},
on_click=lambda: TodoState.set_filter(name),
)
def render_todo_item(todo: rx.Var[dict]) -> rx.Component:
return rx.hstack(
rx.checkbox(
is_checked=todo["done"],
on_change=lambda _: TodoState.toggle(todo["id"]),
size="2",
color_scheme="blue",
),
rx.text(
todo["text"],
flex="1",
color=rx.cond(todo["done"], "gray.500", "white"),
text_decoration=rx.cond(todo["done"], "line-through", "none"),
),
rx.icon_button(
"trash",
color_scheme="red",
variant="soft",
on_click=lambda: TodoState.remove(todo["id"]),
),
align="center",
spacing="3",
width="100%",
)
def todo_input_bar() -> rx.Component:
return rx.hstack(
rx.input(
placeholder="What needs to be done?",
value=TodoState.new_text,
on_change=TodoState.set_new_text,
flex="1",
size="3",
background_color="gray.800",
color="white",
border_color="gray.600",
_placeholder={"color": "gray.400"},
),
rx.button(
"Add",
size="3",
background_color="blue.600",
color="white",
_hover={"background_color": "blue.500"},
on_click=TodoState.add_todo,
),
spacing="3",
width="100%",
)
def todo_list_panel() -> rx.Component:
return rx.vstack(
rx.foreach(TodoState.filtered_todos, render_todo_item),
spacing="2",
width="100%",
)
def footer_bar() -> rx.Component:
return rx.hstack(
rx.text(TodoState.items_left_label, size="2", color="gray.300"),
rx.hstack(
filter_button("all", "All"),
filter_button("active", "Active"),
filter_button("done", "Done"),
spacing="2",
),
rx.button(
"Clear Completed",
variant="soft",
background_color="gray.700",
color="white",
_hover={"background_color": "gray.600"},
on_click=TodoState.clear_completed,
),
justify="between",
align="center",
width="100%",
)
def index() -> rx.Component:
return rx.center(
rx.card(
rx.vstack(
rx.heading("Reflex To-Do", size="6", color="white"),
todo_input_bar(),
rx.separator(border_color="gray.700"),
todo_list_panel(),
rx.separator(margin_y="2", border_color="gray.700"),
footer_bar(),
width="min(720px, 92vw)",
spacing="4",
),
size="4",
width="min(760px, 96vw)",
shadow="lg",
background_color="gray.900",
),
min_h="100vh",
padding_y="8",
background_color="black",
)
app = rx.App()
app.add_page(index, route=" title="Reflex To-Do")
적용 결과는 아래 이미지와 같습니다.
위 코드에서 흐름은 기본적으로 다음과 같이 작동합니다.
- 앱은 작업, 입력 중인 내용, 선택된 필터 등 작은 메모리를 유지합니다.
- 상자에 입력하면 입력한 대로 해당 텍스트가 저장됩니다.
- “추가”를 누르면 작업이 ID와 함께 저장되고 상자가 지워집니다.
- 목록이 즉시 새로 고쳐져 메모리에 있는 내용이 표시됩니다.
- 각 작업 행에는 확인란과 휴지통 아이콘이 있습니다. 토글 완료 확인 중; 휴지통은 작업을 제거합니다.
- 세 개의 필터 버튼(모두/활성/완료)은 표시되는 작업을 변경합니다.
- 바닥글에는 완료되지 않은 작업 수가 표시되며 “완료됨 지우기”를 수행할 수 있습니다.
앞서 다룬 기본 구성 요소 외에 몇 가지 중요한 차이점은 다음과 같습니다.
- 장식하다
@rx.event
주 내에서 이벤트를 선언합니다. - 장식하다
@rx.var
상태에서 파생 변수를 생성합니다. - 사용
rx.Component
Reflex 애플리케이션을 위한 재사용 가능한 UI 도우미를 구축할 때 서명을 사용하세요.
이것이 Reflex의 작동 방식에 대한 기본 설명이자 예입니다. 직접 시도해 보고 순수 Python으로 필요한 웹 애플리케이션을 구축해 보세요.
결론
Reflex는 단순하면서도 직관적인 코드 패턴을 사용하여 순수 Python으로 웹 애플리케이션을 구축할 수 있는 오픈 소스 라이브러리입니다. 간단한 설정과 이해하기 쉬운 코드를 통해 사용자는 로직과 UI를 한 곳에 유지할 수 있습니다. Python으로 애플리케이션을 구축하려는 신규 개발자와 전문 개발자 모두에게 유용한 라이브러리입니다.
이것이 도움이 되었기를 바랍니다.
코넬리우스 유다 위자야 데이터 과학 보조 관리자이자 데이터 작성자입니다. Allianz Indonesia에서 풀타임으로 일하는 동안 그는 소셜 미디어와 글쓰기 미디어를 통해 Python과 데이터 팁을 공유하는 것을 좋아합니다. Cornellius는 다양한 AI 및 기계 학습 주제에 대해 글을 씁니다.
Post Comment