pyLaboratorio 3: CRUD contable
Programación III, laboratorio 3 de 3

CRUD contable con Python, MySQL y PHP

Vas a construir ContaPyme, un sistema administrativo para registrar terceros (clientes y proveedores) y sus movimientos de ingreso y egreso. Primero lo usas y ves qué ocurre en cada capa; después escribes cada pieza: base de datos, clases, repositorio, reglas de negocio, reportes y la conexión con una página web en PHP.

  • Arquitectura en capas
  • Modelo relacional en MySQL
  • POO: herencia y polimorfismo
  • Patrón repositorio
  • Consultas parametrizadas
  • Reglas de negocio
  • Reportes con SQL
  • Integración Python y PHP
Taller guiado con Flask

Si quieres construir el CRUD como aplicación web en tu computador, con WampServer, phpMyAdmin y VS Code, sigue el taller guiado paso a paso. Trae pantallazos de cada paso y el proyecto terminado para comparar.

Este laboratorio sigue las seis fases del proyecto integrador: migración Java a Python (módulo 4), herencia y polimorfismo (módulo 4), modelo de datos (módulo 3), CRUD (módulos 6 y 7), integración (módulo 11) y sustentación (módulo 12). La carpeta recursos/ contiene el proyecto completo en archivos reales para abrir en VS Code y MySQL Workbench.

El caso: ContaPyme

Una pequeña empresa de Cali lleva sus cuentas en una hoja de cálculo que ya no da abasto. Necesita un sistema que cumpla estos requerimientos:

CódigoComo usuario quiero…Operación
RF-01registrar clientes y proveedores con NIT, razón social y correoCreate
RF-02consultar y buscar terceros por nombre o NITRead
RF-03corregir los datos de un terceroUpdate
RF-04eliminar un tercero, siempre que no tenga movimientosDelete
RF-05registrar ingresos y egresos asociados a un terceroCreate
RF-06ver el balance: total de ingresos, egresos y saldo por terceroRead (reporte)

El sistema se organiza en capas. Cada una tiene una sola responsabilidad y solo conversa con la capa vecina:

VistaFormularios y tablas en HTML o menú de consola. Recoge datos y muestra resultados.
ControladorRecibe la petición, decide qué hacer y responde. En la web: un archivo PHP o una ruta de Flask.
Modelo y repositorioClases del negocio (Tercero, Ingreso, Egreso) y la clase que habla con la base de datos.
Base de datosMySQL guarda los datos y protege la integridad con claves y restricciones.
Lo que ya sabes de Java

Es el mismo patrón que usaste con DAO o repositorios en Java. Cambia la sintaxis, no la arquitectura.

Consola CRUD en vivo

Usa ContaPyme como lo haría un usuario. Cada vez que hagas algo, el panel de traza (a la derecha, o debajo en pantallas pequeñas) muestra lo que ocurre por dentro: la petición HTTP que envía el navegador, el código del backend en Python y en PHP, la sentencia SQL y la respuesta. Provoca errores a propósito: repite un NIT, deja campos vacíos o intenta eliminar un tercero que tiene movimientos.

ContaPyme
NITRazón socialTipo

Traza de la operación

Haz cualquier acción en ContaPyme para ver su recorrido por las capas.
Historial de operaciones
    Dinámica recomendada: proyecta la consola y pide al grupo que prediga qué SQL se generará antes de cada clic. Luego provoca los tres errores (NIT repetido, validación y clave foránea) y pregunta en qué capa se detectó cada uno y por qué. La respuesta correcta es la base para el módulo 8.

    Modelo de datos en MySQL

    La base de datos es la última línea de defensa. Aunque el código tenga errores, las restricciones impiden datos inválidos: UNIQUE evita NIT repetidos, FOREIGN KEY impide movimientos sin tercero, CHECK rechaza valores negativos. Ejecuta este script en MySQL Workbench.

    Decisión de diseñoPor qué
    DECIMAL(14,2) para dineroFLOAT guarda aproximaciones; en contabilidad un peso de diferencia es un descuadre.
    ON DELETE RESTRICTBorrar un tercero con historial contable destruiría la trazabilidad. La base lo impide (RF-04).
    ENUM para tipoSolo acepta los valores del negocio; evita "cliente", "Cliente" y "clientes" como si fueran distintos.
    Índice en fechaLos reportes filtran por periodo; el índice (un árbol B+, visto en el laboratorio 2) acelera la búsqueda.
    utf8mb4Guarda tildes, eñes y emojis sin corromperlos.

    Clases del dominio: herencia y polimorfismo

    Cada tabla tiene su clase. @dataclass genera automáticamente el constructor, __repr__ y la comparación, lo que en Java escribías a mano. La validación va en __post_init__: un objeto inválido nunca llega a existir.

    Movimiento es una clase abstracta; Ingreso y Egreso la heredan y cada una implementa signo() a su manera. Eso es polimorfismo: el balance llama al mismo método sin preguntar de qué tipo es cada movimiento.

    Un tercer tipo de movimiento

    Agrega la clase Ajuste, que hereda de Movimiento, tiene tipo = "AJUSTE" y cuyo signo es 1 si el concepto empieza con "+" y -1 en caso contrario. Imprime el efecto en caja de Ajuste(1, "-Faltante de caja", 20000, date(2026, 9, 30)): -20000

    Para la sustentación: pide que expliquen por qué agregar Ajuste no obligó a modificar el cálculo del saldo. Es el principio abierto/cerrado.

    La conexión a la base de datos

    Python habla con MySQL mediante un conector. En clase usarás mysql-connector-python; en este laboratorio los ejemplos ejecutables usan sqlite3, una base de datos que viene incluida en Python y funciona en el navegador. El código del repositorio es el mismo; solo cambian la conexión y el marcador de parámetros.

    Conceptomysql-connectorsqlite3PDO
    Marcador de parámetro%s?? o :nombre
    Ejecutarcur.execute(sql, datos)cur.execute(sql, datos)$stmt->execute($datos)
    Traer filasfetchall()fetchall()fetchAll()
    Id generadocur.lastrowidcur.lastrowid$pdo->lastInsertId()
    Confirmar cambioscon.commit()con.commit()automático, o commit() en transacción
    El error más común

    Olvidar con.commit(). El INSERT parece funcionar, pero al cerrar el programa los datos desaparecen. El gestor de contexto de arriba lo hace por ti.

    El repositorio: las cuatro operaciones

    El repositorio es la única clase que escribe SQL. El resto del programa le pide cosas con métodos claros (crear, listar, actualizar, eliminar) y no sabe si detrás hay MySQL, SQLite o un archivo. Compara cada operación en los tres lenguajes.

    Create: crear

    Read: consultar

    Update: actualizar

    Delete: eliminar

    Taller: CRUD completo ejecutable

    Este es el sistema completo en un solo archivo, funcionando con Python real en tu navegador. Modifícalo, rómpelo y vuelve a ejecutarlo. Cuando lo pases a tu proyecto, separa cada bloque en su archivo (modelos.py, conexion.py, repositorios.py, main.py) y cambia ? por %s.

    Contar por tipo

    Agrega al repositorio el método contar_por_tipo() que use SELECT tipo, COUNT(*) … GROUP BY tipo ORDER BY tipo y devuelva un diccionario. El código de prueba ya está escrito; la salida esperada es {'CLIENTE': 2, 'PROVEEDOR': 1}

    Nota que dict(filas) funciona porque cada fila es una tupla de dos elementos: es la conversión lista de pares a diccionario del laboratorio 2.

    Reglas de negocio y seguridad

    Un dato se valida en tres lugares, y cada uno protege algo distinto:

    CapaQué validaEjemplo en ContaPymeSi falta
    Vista (HTML, JS)Formato, para ayudar al usuariorequired, type="email"Mala experiencia, pero se puede saltar
    Modelo (Python o PHP)Reglas del negocioNIT de 6 a 10 dígitos, valor mayor que ceroEntran datos absurdos por la API
    Base de datosIntegridadUNIQUE, FOREIGN KEY, CHECKDuplicados y registros huérfanos

    La regla más importante de todo el laboratorio: nunca construyas SQL pegando texto del usuario. Ejecuta este ejemplo y mira cómo una búsqueda "inocente" devuelve todos los registros y otra borra la tabla.

    Otras dos reglas que el proyecto debe cumplir

    Las contraseñas nunca se guardan en texto plano: en Python se usa hashlib o bcrypt, en PHP password_hash() y password_verify(). Y todo lo que se imprime en HTML pasa por htmlspecialchars() para evitar que un nombre como <script> se ejecute en el navegador de otro usuario.

    La tabla de usuarios del ejemplo guarda claves en texto plano a propósito, para que el ataque sea visible. Aclara al grupo que es un antiejemplo. Si hay tiempo, pide como reto extra reemplazar la columna clave por un hash con hashlib.sha256 y explicar por qué aun así no es suficiente sin sal (por eso se prefiere bcrypt).

    Reportes: el balance

    Un reporte se puede calcular en SQL o en Python. Regla práctica: filtra y agrupa en SQL (la base de datos lo hace más rápido y envía menos datos) y deja a Python el formato y los cálculos que SQL no expresa bien.

    Mayor cliente

    Escribe una consulta que devuelva el nombre del tercero con más ingresos y su total. Salida esperada: Ferretería Central 1420000.0

    Integración con la web: Python, PHP y MySQL

    Python y PHP no se mezclan en el mismo archivo. Se integran de tres maneras, y elegir la correcta depende de dónde se va a ejecutar cada parte:

    EstrategiaCómo funcionaDónde correCuándo usarla
    A. Base de datos compartidaPython (consola o escritorio) y PHP (web) leen y escriben la misma base MySQL.PHP y MySQL en Hostinger; Python en el equipo, conectado por MySQL remoto.La más simple. Recomendada para el proyecto del curso.
    B. API en PHP, cliente en PythonPHP expone api.php que responde JSON; Python la consume con requests.API en Hostinger; Python en cualquier equipo con internet.Cuando Python no debe tener la contraseña de la base de datos.
    C. API en Python (Flask)Python expone las rutas; la página web (HTML, JS o PHP) las consume.Requiere un servidor que ejecute Python de forma permanente, por ejemplo un VPS.Cuando el backend completo debe ser Python. Practícala en tu equipo con el taller guiado de Flask.
    Limitación real del alojamiento

    Los planes de hosting compartido suelen ejecutar PHP y MySQL, pero no permiten dejar una aplicación Python escuchando peticiones. Por eso, si la página debe quedar publicada en un hosting compartido, las estrategias A y B son las viables. Verifica las condiciones de tu plan antes de decidir.

    La API en PHP (estrategia B)

    Un solo archivo atiende las cuatro operaciones según el método HTTP: GET consulta, POST crea, PUT actualiza, DELETE elimina. Es el mismo contrato que viste en la consola CRUD del módulo 2.

    El cliente en Python

    La página web que consume la API

    Proyecto completo

    Los archivos completos (script SQL, proyecto Python por capas con menú, API en PHP y panel web) se descargan en contapyme-kit.zip, que incluye un archivo LEEME.md que explica cómo instalarlos en el equipo y en el hosting.

    Para que la estrategia A funcione desde los equipos de la institución, hay que habilitar el acceso remoto a MySQL en el panel del hosting y autorizar la IP pública de la sala. Si la red institucional bloquea el puerto 3306, la estrategia B (HTTP por el puerto 443) es la alternativa segura. Pruébalo antes de la sesión.

    Proyecto integrador y evaluación

    Construye tu propio sistema administrativo con la misma arquitectura. Elige un dominio distinto a ContaPyme: inventario de una tienda, control de cartera, nómina simplificada, facturación de un taller o reservas de un consultorio.

    FaseEntregableLaboratorio de apoyo
    1. Migración Java a PythonDos clases de un proyecto Java anterior reescritas en Python con @dataclass y @propertyLab 1, módulo 12
    2. Herencia y polimorfismoJerarquía con clase abstracta y al menos dos subclases con comportamiento propioLab 3, módulo 4
    3. Modelo de datosScript SQL con mínimo dos tablas relacionadas, UNIQUE, FOREIGN KEY y CHECK; diagrama en WorkbenchLab 3, módulo 3
    4. CRUDRepositorio con las cuatro operaciones, consultas parametrizadas y manejo de errores de integridadLab 3, módulos 6 y 7
    5. IntegraciónMenú de consola en Python y una vista web en PHP sobre la misma base de datos (estrategia A o B)Lab 3, módulos 10 y 11
    6. SustentaciónDemostración en vivo, explicación de una decisión de diseño y modificación del código en el momentoTodo el curso

    Rúbrica

    CriterioSuperior (4.6 a 5.0)Alto (4.0 a 4.5)Básico (3.0 a 3.9)Bajo (1.0 a 2.9)
    POOHerencia, clase abstracta y polimorfismo usados donde aportan; validación en el modeloHerencia correcta, validación parcialClases sin herencia realCódigo sin clases o que no ejecuta
    Base de datosRestricciones completas; el sistema maneja cada error de integridad con un mensaje claroRelaciones correctas, manejo parcial de erroresTablas sin claves foráneasSin base de datos funcional
    CRUD y seguridadCuatro operaciones parametrizadas, búsqueda y reporte con GROUP BYCuatro operaciones parametrizadasCRUD incompleto o con SQL concatenadoMenos de dos operaciones
    IntegraciónPython y PHP operan sobre los mismos datos y se demuestra en vivoIntegración funcional con fallas menoresSolo una de las dos partes funcionaSin integración
    SustentaciónExplica decisiones y modifica el código en vivo sin ayudaExplica con claridad, modifica con apoyoDescribe el código sin justificarloNo puede explicar su código
    El criterio de sustentación es el que distingue el trabajo propio del copiado o generado. Una pregunta que funciona bien: "agrega en este momento un campo nuevo a la tabla principal y hazlo visible en el listado". Obliga a tocar las cuatro capas y revela en minutos si el estudiante entiende la arquitectura.