Integraciones
Resumen de integraciones
Usa Pyzed como frontend de escritorio para FastAPI, Django, SQLAlchemy, SQLModel, httpx, Pydantic y aiosqlite, con demos que siguen el tutorial oficial de cada librería.
Pyzed es solo la interfaz: el resto de tu app es Python normal. Por eso las librerías que ya usas para backends web, bases de datos y HTTP funcionan sin cambios en una app de escritorio. Esta sección muestra cómo conectar las más comunes. Cada demo parte del tutorial oficial de la propia librería (el tutorial de SQL de FastAPI, la app de encuestas de Django, el Quick Start de SQLAlchemy, los héroes de SQLModel) y le añade una ventana de Pyzed.
Cuando un backend tiene que ejecutarse junto a la ventana, Arquitecturas explica las cuatro formas de combinarlos, con un diagrama para cada una: mismo proceso, cliente y servidor, servidor integrado y API en el proceso.
| Demo | Librerías | Qué muestra | Tutorial |
|---|---|---|---|
fastapi_heroes |
FastAPI, SQLModel, httpx | La API del tutorial de SQL de FastAPI y un cliente de escritorio para ella, ejecutados de tres formas: servidor aparte, servidor integrado y en el proceso. | FastAPI |
django_polls |
Django, httpx | El tutorial de encuestas de Django, usado desde una ventana con el ORM en el mismo proceso o por HTTP mientras corre runserver. | Django |
sqlalchemy_quickstart |
SQLAlchemy 2.0, aiosqlite | Los usuarios y direcciones del ORM Quick Start, con una Session síncrona en hilos o una AsyncSession en el loop. | SQLAlchemy |
sqlalchemy_contacts |
SQLAlchemy 2.0 | 20.000 filas en una tabla virtual, con búsqueda y orden en SQL desde un hilo de trabajo. | SQLAlchemy |
sqlmodel_heroes |
SQLModel | El tutorial de SQLModel: equipos, héroes, filtros con where(), relaciones y un formulario validado. | SQLModel |
sqlmodel_inventory |
SQLModel, Pydantic | Un solo modelo para validar el formulario y definir la tabla. | SQLModel |
httpx_pypi |
httpx, Pydantic | Peticiones concurrentes que llegan a la ventana a medida que responden, convertidas en modelos. | httpx |
httpx_download |
httpx | Descargas en streaming con barras de progreso y cancelación. | httpx |
pydantic_signup |
Pydantic | Un formulario de registro validado por un modelo, guardado y cargado como JSON. | Pydantic |
aiosqlite_journal |
aiosqlite | Una conexión SQLite async que vive en el loop de Pyzed. | Otras librerías |
Ejecutar una demo
Sección titulada «Ejecutar una demo»Cada demo es un pequeño proyecto de uv. Desde su carpeta:
cd examples/integrations/sqlalchemy_contactsuv run main.pycd examples/integrations/sqlalchemy_contactspython3 -m venv .venvsource .venv/bin/activatepip install pyzed-ui sqlalchemypython main.pycd examples/integrations/sqlalchemy_contactspy -m venv .venv.venv\Scripts\Activate.ps1pip install pyzed-ui sqlalchemypython main.pycd examples/integrations/sqlalchemy_contactspython3 -m pip install pyzed-ui sqlalchemypython3 main.pycd examples/integrations/sqlalchemy_contactspy -m pip install pyzed-ui sqlalchemypy main.pyLa primera vez, uv run crea el entorno virtual e instala las dependencias del pyproject.toml
de la demo. Dentro del repositorio las demos usan tu copia de Pyzed (la tabla
[tool.uv.sources]); para empezar tu propia app a partir de una, copia la carpeta y borra esas
dos líneas para que pyzed-ui venga de PyPI.
Dónde se ejecuta tu código
Sección titulada «Dónde se ejecuta tu código»Una app de Pyzed ejecuta código en tres sitios. Saber en cuál cae cada llamada a una librería es todo lo que hace falta para integrar cualquier cosa:
flowchart LR
UI["Hilo de la UI<br/>view() · update() · callbacks"]
Loop["Loop de asyncio (un hilo)<br/>corrutinas · generadores async"]
Threads["Hilos de trabajo<br/>Command.perform(función)"]
UI -- "devolver una corrutina" --> Loop
UI -- "Command.perform(fn, then)" --> Threads
Loop -- "resultado → update()" --> UI
Threads -- "then(resultado)" --> UI
| La librería es… | Úsala con | Ejemplos |
|---|---|---|
async (await ...) |
Devuelve una corrutina o un generador async desde update, un callback u on_start. Su resultado va a update. |
AsyncClient de httpx, aiosqlite, ORM async de Django, AsyncSession de SQLAlchemy, websockets, redis.asyncio |
| bloqueante | Command.perform(función, then): función corre en un hilo y then(resultado) en el hilo de la UI. |
Sesiones de SQLAlchemy y SQLModel, requests, pandas, archivos |
| un servidor | Ejecútalo aparte (fastapi dev, manage.py runserver) o en un hilo daemon antes de pz.run. Mira Arquitecturas. |
FastAPI, Django, Starlette |
| un stream | pz.listen(generador_async) en subscriptions(). |
websockets, server-sent events, pub/sub de Redis |
Tres reglas lo mantienen seguro:
- Modifica
selfen el hilo de la UI. Las corrutinas y los hilos devuelven resultados;updateothenlos guardan. Leerselfdesde una corrutina está bien. - No bloquees nunca el hilo de la UI. Una consulta de 50 ms congela la ventana 50 ms. Usa
Command.performo una librería async. - Descarta respuestas viejas. Mientras el usuario escribe una búsqueda, los resultados
pueden llegar desordenados. Envía la consulta junto con la petición y descarta las respuestas
de una anterior (todas las demos lo hacen en su manejador
loaded).
Todas las corrutinas comparten un loop de asyncio (pz.asyncio_loop()), así que los objetos
atados a un loop, como un httpx.AsyncClient o una conexión de aiosqlite, se crean una vez y
se reutilizan.
Errores de validación en cada campo
Sección titulada «Errores de validación en cada campo»La mayoría de los backends informan de una entrada inválida con una lista de errores por campo.
pz.validation_errors(error) convierte cualquiera de ellos en {campo: mensaje}, y
ui.field(..., error=) muestra el mensaje bajo el título del campo, con el color de error del
tema:
from pydantic import ValidationError
def save(self): try: item = ItemIn.model_validate(self.draft) except ValidationError as error: self.errors = pz.validation_errors(error) return ...
def view(self): return ui.field("Price", ui.input(self.draft["price"], self.set_price), error=self.errors.get("price"))Entiende:
ValidationErrorde Pydantic y SQLModel (los mensajes de tusValueErrorpierden el prefijoValue error,),- el JSON de una respuesta 422 de FastAPI,
{"detail": [...]}, sin la partebody/queryde cada ubicación, y un{"detail": "Not found"}simple, - el
ValidationErrorde Django que lanzafull_clean()(los errores__all__usan la clave"").
Los campos anidados se unen con puntos ("address.city") y los errores que no son de ningún
campo usan la clave "", que las demos muestran en un ui.callout.
Selects con objetos
Sección titulada «Selects con objetos»ui.select acepta cualquier objeto como opción y lo muestra con str(): un modelo de Django, un
enum, una dataclass. on_select recibe el objeto, no su texto:
ui.select(self.authors, self.draft["author"], lambda author: self.draft.update(author=author))