Usando Mountaineer para desarrollar una aplicación React con Python

Mountaineer es un framework para crear aplicaciones web en Python y React fácilmente. Su idea es que el desarrollador aproveche sus conocimientos previos de Python y TypeScript para usar cada lenguaje (y framework) en la tarea que mejor se adapta a sus necesidades.

La idea básica es desarrollar el frontend como una aplicación React adecuada y el backend como varios servicios Python: todo en un solo proyecto, tipos consistentes hacia arriba y hacia abajo en la pila, enlace de datos y llamada de funciones simplificados, y renderizado del servidor para una mejor accesibilidad.

En este artículo, describiremos la configuración de un proyecto Mountaineer y mostraremos cómo desarrollar una aplicación sencilla que incluya todos los conceptos básicos. Al finalizar, podrás integrar a la perfección los componentes frontend y backend en un solo proyecto.

Table
  1. Configuración del entorno de desarrollo de Mountaineer
  2. Agregar el controlador y la vista
  3. Añadiendo el modelo
  4. Conclusión

Configuración del entorno de desarrollo de Mountaineer

Antes de empezar, es importante configurar un entorno adecuado. Mountaineer básicamente traslada un proyecto React, que es una aplicación Node, a un entorno Python. Por lo tanto, puede ser bastante exigente con las versiones de cada componente del entorno.

Cómo analizar los paquetes de aplicaciones de Next.js

En mi configuración, WSL ejecuta una versión bastante antigua de Ubuntu (Ubuntu 20.04.6 LTS) en Windows, por lo que tuve que actualizar los siguientes paquetes:

  • Lenguaje Rust: Actualizado a la versión mayor o igual a 1.77
  • Go language: Actualizado a la versión 1.22
  • Nodo: Actualizado a versión mayor o igual a 20
  • Lenguaje Python: Actualizado a la versión mayor o igual a 3.11

Esta configuración cambiará una vez que Mountaineer se estabilice. Cabe mencionar que el autor fue muy receptivo y me brindó apoyo cuando tuve problemas al configurar el sistema.

Una vez configurado su entorno, puede crear una aplicación repetitiva utilizando el siguiente comando:

Pipx Run Create - Alpinista - Aplicación

Esta es la función disponible para crear la estructura de directorio (bastante compleja) con todas las dependencias de los dos entornos coexistentes: el proyecto Python y el proyecto Node.

Cómo integrar WunderGraph con su aplicación frontend

En la siguiente figura se puede observar la salida del comando, que puede variar dependiendo de los requisitos preexistentes:

$ pipx ejecutar crear - montañero - aplicación? Nombre del proyecto [mi-proyecto]: microblog? Autor [ Rosario De Chiara rosdec@gmail.com ] ? ¿Usar poesía para la gestión de dependencias? [ Sí ] Sí ? ¿Crear archivos MVC de stub? [Sí] ¿No? ¿Usar Tailwind CSS? [Sí] ¿No? ¿Añadir configuración del editor? [vscode] vscode Creando proyecto... Creando. gitignore Creando docker-compose. yml Creando README. md Creando pyproject. toml Creando . env Creando microblog/aplicación. py Creando microblog/principal. py Creando microblog/cli. py Creando microblog/config. py Creando microblog/__init__. py Creando microblog/vistas/paquete. json No se detectó contenido en microblog/views/tailwind. configuración. js, omitiendo... No se detectó contenido en microblog/views/postcss. configuración. js, omitiendo... No se detectó contenido en microblog/views/__init__. py, omitiendo... No se detectó contenido en microblog/views/app/main. css, omitiendo... No se detectó contenido en microblog/views/app/home/page. tsx, omitiendo... No se detectó contenido en microblog/views/app/detail/page. tsx, saltando... No se detectó contenido en microblog/controladores/home. py , saltando... No se detectó contenido en microblog/controladores/home. microblog/controllers/detalle.py, omitiendo... Creando microblog/controllers/__ init__.py No se detectó contenido en microblog/models/detalle.py, omitiendo... Creando microblog/models/__init__.py Proyecto creado en / home/user/microblog Creando microblog virtualenv - IiOnN0qh - py3.11 es /home/user/.cache/pypoetry/virtualenvs Actualizando dependencias Resolviendo dependencias... ( 1.3s )​​​​​​​​​​​​​ Operaciones de paquete : 29 instalaciones , 0 actualizaciones , 0 eliminaciones [.... INSTALACIÓN DE PAQUETES DE PYTHON ....]Escritura de archivo de bloqueoInstalando el proyecto actual : microblog ( 0.1.0 ) Poetry venv creado : /home/user/.cache/pypoetry/virtualenvs/microblog-IiOnN0qh-py3.11​​Se agregaron 129 paquetes y se auditaron 130 paquetes en 9 segundos. 34 paquetes buscan financiación Ejecute ` npm fund` para obtener más detalles Se encontraron 0 vulnerabilidades Entorno creado exitosamente Creando . vscode/configuración. json Configuración del editor creado en / home / usuario / microblog $

Si observa con atención, puede distinguir dos fases de instalación de dependencias. Observa cómo no solo genera el andamiaje de la aplicación, sino que también lo llena con un proyecto MVC de ejemplo.create-mountaineer-app

Para este artículo, no utilizaremos esta función, pero implementaremos una aplicación de muestra a mano con este comando:

  $ poesía ejecutar servidor

Podrás iniciar el servidor web (ver http://127.0.0.1:5006/ ) y comenzar a desarrollar la aplicación con la útil recarga en caliente una vez modificado el código fuente.

Desarrollo de aplicaciones multiplataforma con Bun v1.1

Debo admitir que la primera ejecución no es muy emocionante: no hay ninguna página cargada y el resultado es bastante aburrido:

Antes de comenzar el desarrollo, veamos la estructura de directorios creados por el script que acabamos de ejecutar. A partir de las descripciones, deberías poder entender dónde concentrarte según lo que pretendes hacer:

Agregar el controlador y la vista

Crear una página implica configurar un nuevo controlador para definir los datos que se pueden enviar y recibir en el frontend.

Creemos un controlador llamado en el directorio controlador; como controlador, se ejecutará en el backend y, como probablemente esperes, es un script de Python.home.py

Uso de Storybook y RSC para crear y probar aplicaciones de forma aislada

La idea general es tener una instancia de la ControllerBaseclase e implementar el método render que proporciona la carga de datos sin procesar que se envía al frontend en la representación inicial y durante cualquier actualización de efectos secundarios.

En la mayoría de los casos, debería devolver una RenderBaseinstancia (ver más abajo), pero si no tiene datos que mostrar, también puede devolver None, como en este caso. Además, debemos configurar el urlparámetro que contiene la URL accesible al controlador y el view_pathque asocia la vista a este controlador.

La función es un componente fundamental de Mountaineer y todos los controladores deben tener una: define todos los datos que su interfaz necesitará para resolver su vista:render()

Desde la importación de montañero ControllerBase clase HomeController ( ControllerBase ): url = "/" view_path = "/app/home/page.tsx" async def render ( self ) - Ninguno : pasar          

El siguiente paso es registrar el nuevo controlador en:app.py

el montañero. aplicación importante AppController de montañero. js_compiler. postcss importa PostCSSBundler de montañero. render importar LinkAttribute, Metadatos de intro_to_mountaineer. config importa AppConfig de intro_to_mountaineer. controladores. home importar HomeController controlador = AppController ( config = AppConfig (), # tipo: ignorar ) controlador .registrar ( HomeController ( ) )

En este punto, si guarda su archivo, el servidor se recargará automáticamente, registrando el nuevo controlador pero quejándose de la falta, que es la vista que hemos asociado con el nuevo controlador.page.tsx



La vista es, por supuesto, un archivo TypeScript/React:

importar React desde "react" ; importar {useServer} desde "./_server/useServer"; const Inicio = () = { const EstadoServidor = useServer (); return (div h1 Inicio / h1 p ¡Hola, mundo! / p/div); }; exportar predeterminado Inicio ;  

Debes crear la ruta del directorio donde se encuentra nuestro proyecto React y colocar el archivo arriba, llamado ./app/home//view/page.tsx

Si colocaste todo en los lugares correctos, tu navegador se actualizará y mostrará la página recién creada:

Si tiene un problema al colocar el archivo correcto en el directorio, verifique esta confirmación específica en el repositorio y vea cómo se ve la aplicación.

Añadiendo el modelo

Una idea inteligente de Mountaineer es que admite una base de datos PostgresSQL para respaldar tus datos. Para facilitar su uso, junto con los archivos de tu proyecto, el create_mountaineer_appscript también crea un archivo YAML para iniciar el servidor PostgresSQL en tu Docker. No tienes que encargarte de la creación de tablas; Mountaineer simplemente inspeccionará tu código en el directorio para comprender qué objetos necesitas en la base de datos.docker-compose.yml/model

El primer paso es crear un nuevo script de Python. En este ejemplo, estará en el directorio:blogpost.py/model

de montañista. base de datos importar SQLModel , Campo de uuid importar UUID , uuid4 de datetime importar datetime clase BlogPost ( SQLModel , tabla = True ): id : UUID = Campo ( default_factory = uuid4 , clave_principal = True ) texto : cadena de datos : str = datetime.now ( )​

Para agregar este archivo al proyecto, debes incluirlo en el archivo Python:__init__.py

desde .blogpost importar BlogPost​  

En este punto, estamos listos para crear la tabla en la base de datos con los siguientes comandos. Por supuesto, necesita tener una docker instalación en su sistema para instanciar el contenedor:

  docker - componer - d carrera de poesía creadab

El createdbscript estará en el directorio y, para cada objeto que se haya incluido en el archivo de inicialización, creará una tabla con columnas que coincidan con los nombres y tipos definidos en el archivo (para este ejemplo)./model __init__.pyblogpost.py

Por curiosidad, si revisas tu base de datos PostgresSQL, podrás ver la estructura de la blogposttabla:

Ahora tenemos todos los elementos listos para completar el desarrollo de la aplicación. Primero, agregaremos la funcionalidad para agregar una nueva entrada de blog. Para ello, debemos agregar los campos de entrada al frontend (en el directorio) y actualizar el controlador para que añada correctamente una fila a la tabla (en el directorio)./viewsblogpost/controllers

Primero agregamos un nuevo método en el backend, que es el controlador, en el archivo (el archivo completo está en el repositorio):/controllers/home.py

clase HomeController(ControllerBase): url = "/" view_path = "/app/home/page.tsx" async def render(self) - Ninguno: aprobar @sideeffect async def add_blogpost(self, payload: str, session: AsyncSession = Depends(DatabaseDependencies.get_db_session)) - Ninguno: new_blogpost = BlogPost(text = payload) session.add(new_blogpost) await session.commit()                      

En el código anterior, definimos el método add_blogpostmarcado por el @sideeffectdecorador. Esto le indica a Mountaineer que este código tendrá un impacto en los datos y, por lo tanto, al invocarlo, se debe recargar el estado del servidor.



El add_blogpostmétodo simplemente ingresará el parámetro payload, que contendrá todos los datos transferidos desde el backend y la sesión que contiene el puntero a la base de datos. Al usar el payload, creamos una nueva BlogPostinstancia de objeto, inicializándola con la cadena de payload. El new_blogpostobjeto se añade a la sesión, lo que se traduce en una inserción en la tabla Blogpost de la base de datos.

La segunda modificación se encuentra en la vista. A continuación, se muestra un fragmento del archivo (el archivo completo está en el repositorio):page.tsx /views/app/home

const CreatePost = ({ serverState }: { serverState : ServerState }) = { const [ newBlogpost , setNewBlogpost ] = useState ( "" ); return ( div tipo de entrada = "texto" valor ={ newBlogpost } onChange ={( e ) = setNewBlogpost ( e . target . value )} / botón onClick ={ async () = { await serverState.add_blogpost ({ payload : newBlogpost.toString () }); setNewBlogpost ( " " ) ; } } Publicación/botón /div );};

En el frontend, definimos un nuevo componente de React que es simplemente un formulario simple para gestionar el cuadro de texto y el onClickevento al enviarlo. Como se puede ver en el código anterior, simplemente invocamos el servicio de backend add_blogpostdefinido en el controlador.

En la siguiente imagen, puedes ver el verdadero superpoder de Mountaineer: la fuerte interconexión entre el proyecto Python y el proyecto React/TypeScript:

En la sección de React/TypeScript del bloque de código anterior, vemos la nueva función, add_blogpost(), añadida al controlador sin necesidad de configuración adicional. Cada vez que modificamos el código fuente, Mountaineer incorpora las modificaciones actualizando las sugerencias de tipo y de función.

Una vez que completes todas las modificaciones en el navegador, podrás ver la nueva interfaz de usuario:

Al interactuar con el formulario consultando la base de datos podrás ver que todo el proceso funciona:

Ahora tenemos un flujo de datos adecuado desde el frontend hasta la base de datos a través del backend. El último paso es implementar el flujo en sentido inverso, de la base de datos al frontend. Esto implicará cambios en dos puntos: el controlador y la vista.

El controlador tendrá una nueva versión de la renderfunción:

    async def render(self, request: Solicitud, session: AsyncSession = Depends(DatabaseDependencies.get_db_session) ) - HomeRender: posts = await session.execute(select(BlogPost)) return HomeRender(posts=posts.scalars().all() )

renderSe invoca durante el renderizado inicial y en cualquier sideeffectactualización. Su propósito es proporcionar los datos de la base de datos que se enviarán al frontend. Las actualizaciones se actualizan en el estado del servidor mediante la RenderBaseinstancia. En el ejemplo anterior, se puede ver cómo se llena la matriz `name` postsal ejecutar una consulta en el objeto específico BlogPost.

En la vista, solo tenemos que manipular los datos serverStatey ensamblarlos en la interfaz: para este propósito, escribimos un nuevo componente React llamado ShowPosts:

const ShowPosts = ({ serverState }: { serverState: ServerState }) = { return ( serverState.posts.map((post) = ( div key={post.id} div{post.text}/div div{post.data}/div br/br /div )))}

Ya sabemos que en el serverStateobjeto, encontraremos un objeto llamado postsque se rellena en el controlador anterior. Los archivos actualizados están en el repositorio y el resultado final es el siguiente:

Conclusión

Este proyecto tiene algunas similitudes con proyectos como ReactPy y PyReact. Sin embargo, a diferencia de estos, permite integrar tanto el frontend escrito en TypSscript/React puro como el backend en Python/Uvicorn puro en una única condebase, logrando un fuerte acoplamiento entre ambas capas mediante Mountaineer.

Empieza ahora

Si quieres conocer otros artículos parecidos a Usando Mountaineer para desarrollar una aplicación React con Python puedes visitar la categoría Aplicaciones.

Entradas Relacionadas