Guzmán D. Darío Senior Python Developer Español Hire me
Taller autoguiado

Cargo Track: Diseña una API de rastreo logístico con FastAPI

Paso 16 de 19
Paso 16 de 19

Streamlit: módulo de Clientes y Conductores

En este paso construyes los módulos de Clientes y Conductores. Siguen el mismo patrón del módulo de Envíos: tabs para listar y crear, con formularios y mensajes de error claros.

Módulo de Clientes

Crea cargo_track_ui/pages/clientes.py:

cargo_track_ui/pages/clientes.py python
import streamlit as st
from api_client import get, post, APIError


def mostrar():
    st.title("Gestión de Clientes")

    tab_lista, tab_crear = st.tabs(["Ver clientes", "Nuevo cliente"])

    with tab_lista:
        _tab_lista()
    with tab_crear:
        _tab_crear()


def _tab_lista():
    st.subheader("Clientes registrados")

    with st.spinner("Cargando clientes..."):
        try:
            clientes = get("/clientes/")
        except APIError as e:
            st.error(f"Error {e.status_code}: {e.mensaje}")
            return
        except Exception:
            st.error("No se pudo conectar con el API.")
            return

    if not clientes:
        st.info("No hay clientes registrados.")
        return

    st.dataframe(
        clientes,
        column_config={
            "id": "ID",
            "nombre": "Nombre",
            "email": "Correo",
            "telefono": "Teléfono",
        },
        use_container_width=True,
        hide_index=True,
    )


def _tab_crear():
    st.subheader("Registrar nuevo cliente")

    with st.form("form_crear_cliente"):
        nombre = st.text_input("Nombre completo")
        email = st.text_input("Correo electrónico")
        telefono = st.text_input("Teléfono (opcional)")
        enviado = st.form_submit_button("Registrar cliente", use_container_width=True)

    if enviado:
        if not nombre or not email:
            st.warning("El nombre y el correo son obligatorios.")
            return
        try:
            nuevo = post("/clientes/", {
                "nombre": nombre,
                "email": email,
                "telefono": telefono or None,
            })
            st.success(f"Cliente '{nuevo['nombre']}' registrado con ID #{nuevo['id']}.")
        except APIError as e:
            st.error(f"Error {e.status_code}: {e.mensaje}")
        except Exception:
            st.error("No se pudo conectar con el API.")

El router de conductores en el API

Antes de crear el módulo en Streamlit, necesitas el router en el API. Crea cargo_track/routers/conductores.py:

cargo_track/routers/conductores.py python
from fastapi import APIRouter, Depends, HTTPException
from sqlmodel import Session, select
from ..database import get_session
from ..models import Conductor
from ..schemas import ConductorCreate, ConductorRead
from ..auth import verificar_api_key

router = APIRouter(prefix="/conductores", tags=["Conductores"])


@router.get("/", response_model=list[ConductorRead])
def listar_conductores(session: Session = Depends(get_session)):
    return session.exec(select(Conductor)).all()


@router.get("/{conductor_id}", response_model=ConductorRead)
def obtener_conductor(conductor_id: int, session: Session = Depends(get_session)):
    conductor = session.get(Conductor, conductor_id)
    if not conductor:
        raise HTTPException(status_code=404, detail="Conductor no encontrado")
    return conductor


@router.post("/", response_model=ConductorRead, status_code=201)
def crear_conductor(
    conductor: ConductorCreate,
    session: Session = Depends(get_session),
    _: str = Depends(verificar_api_key),
):
    db_conductor = Conductor.model_validate(conductor)
    session.add(db_conductor)
    session.commit()
    session.refresh(db_conductor)
    return db_conductor

Registra el nuevo router en main.py:

cargo_track/main.py (agregar import y router) python
from .routers import envios, clientes, conductores

# dentro de la app, después de los otros routers:
app.include_router(conductores.router)

Módulo de Conductores en Streamlit

Crea cargo_track_ui/pages/conductores.py:

cargo_track_ui/pages/conductores.py python
import streamlit as st
from api_client import get, post, APIError


def mostrar():
    st.title("Gestión de Conductores")

    tab_lista, tab_crear = st.tabs(["Ver conductores", "Nuevo conductor"])

    with tab_lista:
        _tab_lista()
    with tab_crear:
        _tab_crear()


def _tab_lista():
    st.subheader("Conductores registrados")

    with st.spinner("Cargando conductores..."):
        try:
            conductores = get("/conductores/")
        except APIError as e:
            st.error(f"Error {e.status_code}: {e.mensaje}")
            return
        except Exception:
            st.error("No se pudo conectar con el API.")
            return

    if not conductores:
        st.info("No hay conductores registrados.")
        return

    st.dataframe(
        conductores,
        column_config={
            "id": "ID",
            "nombre": "Nombre",
            "licencia": "Licencia",
            "email": "Correo",
        },
        use_container_width=True,
        hide_index=True,
    )


def _tab_crear():
    st.subheader("Registrar nuevo conductor")

    with st.form("form_crear_conductor"):
        nombre = st.text_input("Nombre completo")
        licencia = st.text_input("Número de licencia")
        email = st.text_input("Correo electrónico")
        enviado = st.form_submit_button("Registrar conductor", use_container_width=True)

    if enviado:
        if not nombre or not licencia or not email:
            st.warning("Todos los campos son obligatorios.")
            return
        try:
            nuevo = post("/conductores/", {
                "nombre": nombre,
                "licencia": licencia,
                "email": email,
            })
            st.success(f"Conductor '{nuevo['nombre']}' registrado con ID #{nuevo['id']}.")
        except APIError as e:
            st.error(f"Error {e.status_code}: {e.mensaje}")
        except Exception:
            st.error("No se pudo conectar con el API.")

Checkpoint

Prueba los dos módulos nuevos con el API corriendo:

  1. En "Clientes": registra un cliente y verifica que aparece en la tabla de la tab "Ver clientes"
  2. En "Conductores": registra un conductor y verifica que aparece en la tabla
  3. Intenta registrar un cliente con el mismo email dos veces y observa el mensaje de error que muestra Streamlit

Si los tres puntos funcionan, los módulos están completos.

Guarda tu progreso

Haz un commit con los cambios de este paso:

terminal bash
git add cargo_track_ui/pages/clientes.py cargo_track_ui/pages/conductores.py cargo_track/routers/conductores.py cargo_track/main.py
git commit -m "feat: agregar módulos de clientes y conductores en frontend y API"