Last active
February 7, 2024 05:06
-
-
Save hgrecco/c33a1596044cd65b886dc55bc339dcaf to your computer and use it in GitHub Desktop.
Dynamic reflex pages based on models
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from dataclasses import dataclass | |
from typing import Iterable, Any, Sequence, NamedTuple | |
import stringcase | |
import reflex as rx | |
from sqlmodel import select | |
class FormField(NamedTuple): | |
field_name: str | |
model_field: rx.base.ModelField | |
@property | |
def placeholder(self) -> str: | |
return stringcase.sentencecase(form_field.field_name) | |
def render(self): | |
# TODO: Create specific input fields according to the annotation | |
# and field information. | |
return rx.input( | |
name="abc", | |
placeholder="def", | |
) | |
class DynamicFormState[T: rx.Model]: | |
form_data: dict[str, Any] | |
_include_fields: tuple[str] | None = None | |
_exclude_fields: tuple[str] = tuple[str]() | |
_model: type[rx.Model] | |
records: list[T] = list[T]() | |
def load_records(self): | |
with rx.session() as session: | |
self.records = session.exec(select(self._model)).all() | |
yield None | |
@classmethod | |
def model_fields(cls) -> list[tuple[str, rx.base.ModelField]]: | |
return list(cls._model_fields()) | |
@classmethod | |
def _model_fields(cls) -> Iterable[tuple[str, rx.base.ModelField]]: | |
for field_name, model_value in cls._model.get_fields().items(): | |
if field_name in cls._exclude_fields: | |
continue | |
if cls._include_fields is not None and field_name not in cls._include_fields: | |
continue | |
assert isinstance(model_value, rx.base.ModelField) | |
yield field_name, model_value | |
@classmethod | |
def form_fields(cls) -> list[FormField]: | |
print(cls.model_fields()) | |
print(list(cls._model.get_fields().items())) | |
return list(cls._form_fields()) | |
@classmethod | |
def _form_fields(cls) -> Iterable[FormField]: | |
for field_name, model_field in cls._model_fields(): | |
yield FormField(field_name, model_field) | |
@classmethod | |
def handle_submit(cls, form_data: dict[str, Any]): | |
cls.form_data = form_data | |
# TODO: store in database | |
return rx.redirect("/") | |
######## | |
# Pages | |
######## | |
@classmethod | |
def list_page(cls, columns: list[str]) -> rx.Component: | |
return rx.vstack( | |
rx.hstack( | |
rx.heading(cls._model.__name__, font_size="3em"), | |
), | |
# Auto columns | |
rx.data_table( | |
columns=columns, | |
data = cls.records, | |
pagination= True, | |
search= True, | |
sort= True, | |
) | |
) | |
@classmethod | |
def add_page(cls) -> rx.Component: | |
return rx.vstack( | |
rx.form( | |
rx.vstack( | |
rx.foreach( | |
cls.form_fields(), | |
FormField.render | |
), | |
rx.button("Submit", type_="submit"), | |
), | |
on_submit=cls.handle_submit, | |
reset_on_submit=True, | |
), | |
) | |
# TODO: edit and delete pages |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""The dashboard page.""" | |
from typing import Any, Iterable, Sequence | |
import reflex as rx | |
from myapp.templates import template | |
from ..state import State | |
from sqlmodel import Field, select | |
from . import _dynamic_form as dnf | |
class Person(rx.Model, table=True): | |
last_name: str = Field() | |
first_name: str = Field() | |
class PersonState(State, dnf.DynamicFormState[Person]): | |
"""The app state.""" | |
_model = Person | |
@template(route="/persona/list", title="Personas", on_load=PersonState.load_records) | |
def persona_list() -> rx.Component: | |
"""The dashboard page. | |
Returns: | |
The UI for the dashboard page. | |
""" | |
return PersonState.list_page(columns=["last_name", "first_name"]) | |
@template(route="/persona/add", title="Agregar Persona") | |
def persona_add() -> rx.Component: | |
"""The dashboard page. | |
Returns: | |
The UI for the dashboard page. | |
""" | |
return PersonState.add_page() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment