Arquitecturas
Una ventana de Pyzed es un programa de Python, así que una librería de backend puede colocarse a su lado de cuatro formas distintas. La elección depende de una pregunta: ¿quién más necesita los datos?
| Arquitectura | Quién usa los datos | Red | Demos |
|---|---|---|---|
| 1. Mismo proceso | Solo esta app de escritorio | Ninguna | SQLAlchemy, SQLModel, ORM de Django, aiosqlite, Pydantic |
| 2. Cliente y servidor | Una web, una app móvil, otros usuarios | HTTP a un servidor | FastAPI client.py, Django client.py, httpx |
| 3. Servidor integrado | Esta app y otros programas del mismo ordenador | Puerto local | FastAPI embedded.py |
| 4. API en el proceso | Solo esta app, pero el código es una API | Ninguna | FastAPI in_process.py |
Las cuatro pueden compartir el mismo código: los modelos y la API no saben si los llama una ventana, un navegador o un test. Eso es lo que permite que una app empiece con la arquitectura 1 y pase a la 2 más adelante.
1. Mismo proceso
Sección titulada «1. Mismo proceso»La ventana importa la librería y la llama directamente. No hay servidor y nada escucha en la red. Es la opción por defecto para una app de escritorio con su propia base de datos.
flowchart LR
subgraph app["Tu programa (uv run main.py)"]
W["Ventana de Pyzed<br/>view · update"]
T["Hilos de trabajo<br/>Command.perform"]
L["Loop de asyncio<br/>corrutinas"]
M["Modelos y consultas<br/>SQLAlchemy · SQLModel · ORM de Django"]
W --> T --> M
W --> L --> M
end
M --> DB[("SQLite / PostgreSQL")]
- Las librerías bloqueantes (una
Sessionde SQLAlchemy, SQLModel, el ORM de Django) corren en un hilo de trabajo conCommand.perform(función, then). - Las librerías async (
AsyncSession, aiosqlite) corren como corrutinas en el loop de Pyzed. - La base de datos se puede seguir compartiendo: el
desktop.pyde la demo de Django ymanage.py runserverusan el mismodb.sqlite3a la vez.
Demos: sqlalchemy_quickstart (los dos backends),
sqlmodel_heroes, django_polls desktop.py,
aiosqlite_journal, pydantic_signup.
2. Cliente y servidor
Sección titulada «2. Cliente y servidor»El backend es un programa aparte, que se arranca con su propia herramienta (fastapi dev,
manage.py runserver, un despliegue en un servidor). La ventana es un cliente más y solo habla
HTTP, normalmente con httpx.
flowchart LR
subgraph server["Proceso del servidor (fastapi dev main.py · manage.py runserver)"]
API["FastAPI / Django<br/>rutas y vistas"] --> DB[("Base de datos")]
end
subgraph desktop["Proceso de escritorio (uv run client.py)"]
W["Ventana de Pyzed"] --> H["httpx.AsyncClient"]
end
H -- "HTTP / JSON" --> API
B["Navegador · app móvil"] -- "HTTP" --> API
- Úsala cuando los datos se deben compartir entre usuarios o dispositivos, o cuando la API ya existe.
- La ventana no necesita tener instalados ni el driver de la base de datos ni el framework del backend.
- Los errores llegan como códigos HTTP: un 422 de FastAPI va directo a
pz.validation_errors.
Demos: fastapi_heroes client.py, django_polls
client.py, httpx_pypi (una API pública).
3. Servidor integrado
Sección titulada «3. Servidor integrado»Un solo programa arranca la API en un hilo en segundo plano con Uvicorn y luego abre la ventana. La API está disponible en un puerto local mientras la ventana está abierta, para un navegador, un script u otra app.
flowchart LR
subgraph app["Tu programa (uv run embedded.py)"]
direction LR
W["Ventana de Pyzed<br/>hilo principal"] -- "httpx" --> U
U["Uvicorn en un hilo daemon<br/>app de FastAPI"] --> DB[("Base de datos")]
end
B["Navegador en /docs<br/>otros programas locales"] -- "http://127.0.0.1:8000" --> U
- Úsala para una herramienta que también expone una API o una página web, como un panel local o un dispositivo que recibe webhooks.
- El servidor se detiene con la ventana, porque su hilo es daemon.
- Escucha en
127.0.0.1salvo que otros ordenadores tengan que conectarse.
Demo: fastapi_heroes embedded.py.
4. API en el proceso
Sección titulada «4. API en el proceso»httpx puede enviar peticiones directamente a una app ASGI con httpx.ASGITransport, sin servidor
ni puerto. El código se escribe como una API y un cliente, pero se ejecuta como un único programa
sin conexión.
flowchart LR
subgraph app["Tu programa (uv run in_process.py)"]
W["Ventana de Pyzed"] --> H["httpx.AsyncClient<br/>transport=ASGITransport(app)"]
H -- "llamada a función, sin red" --> API["App de FastAPI"]
API --> DB[("Base de datos")]
end
- Úsala para distribuir la misma API como una app de escritorio que funciona sin conexión, o para probar el cliente.
ASGITransportno ejecuta los eventos de startup ni de lifespan: llama tú mismo a tu código de inicialización.
Demo: fastapi_heroes in_process.py.
Cuál encaja con cada librería
Sección titulada «Cuál encaja con cada librería»| Librería | Mismo proceso | Cliente y servidor | Servidor integrado | API en el proceso |
|---|---|---|---|---|
| FastAPI | Solo importar sus modelos | ✅ fastapi dev / fastapi run |
✅ Uvicorn en un hilo | ✅ ASGITransport |
| Django | ✅ ORM tras django.setup() |
✅ manage.py runserver |
No recomendado: ejecútalo aparte | Posible con su app ASGI |
| SQLAlchemy | ✅ Session o AsyncSession |
Detrás de tu API | — | — |
| SQLModel | ✅ Session |
Detrás de FastAPI | — | — |
| httpx | — | ✅ el cliente | ✅ el cliente | ✅ el transporte |
| Pydantic | ✅ valida el formulario | ✅ convierte las respuestas | ✅ | ✅ |
| aiosqlite | ✅ en el loop de Pyzed | — | — | — |
Estructura de un proyecto
Sección titulada «Estructura de un proyecto»Mantén el backend libre de Pyzed y la ventana libre de SQL. Todas las demos siguen esta estructura, que permite que el mismo backend sirva a una ventana, a una API y a los tests:
myapp/├── pyproject.toml├── models.py # modelos de SQLModel / SQLAlchemy / Django, esquemas de Pydantic├── db.py # las consultas, una función por acción, sin imports de Pyzed├── main.py # app de FastAPI o proyecto de Django (cuando hay servidor)└── window.py # la App de Pyzed: llama a db.py o a la API