pyTaller guiado: CRUD con Flask
Programación III, taller guiado del laboratorio 3

CRUD con Python, Flask y MySQL paso a paso

Vas a construir en tu computador una aplicación web que registra, consulta, edita y elimina los terceros de ContaPyme. La base de datos vive en MySQL (WampServer), el código en Python con Flask y lo escribes en VS Code. Cada paso trae el pantallazo de lo que deberías ver.

  • WampServer y phpMyAdmin
  • Entorno virtual
  • Flask: rutas y plantillas
  • mysql-connector
  • Consultas parametrizadas
  • CRUD completo en la web

Descargar el proyecto terminado (.zip) Úsalo para comparar, no para copiar: la sustentación pide modificarlo en vivo.

Esta guía persigue el mismo resultado del video de referencia (CRUD con Python, MySQL y Flask), adaptado al caso ContaPyme del laboratorio 3. El código de esta página se probó completo: crear, listar, buscar, editar, eliminar, NIT duplicado, validaciones y rutas inexistentes. Si el video y la guía difieren en algún detalle, esta versión es la verificada.

Pantallazos. Los que aún no existen aparecen como un recuadro que describe lo que el estudiante debe ver. Para reemplazarlos, guarda tu captura con el nombre que indica el recuadro (visible solo en modo docente) dentro de assets/img/pasos/. Acepta .webp; si tu captura es .png, cambia la extensión en el atributo src de esta página.

Qué vas a construir

Una aplicación web con tres piezas que conversan entre sí. Tu navegador le pide páginas a Flask; Flask ejecuta tu código Python, consulta MySQL y devuelve el HTML ya armado.

Navegadorhttp://127.0.0.1:5000 muestra formularios y la tabla de terceros
Flask (Python)app.py recibe cada petición y decide qué hacer. Corre en el puerto 5000
MySQL (WampServer)Base contapyme_flask, tabla terceros. Puerto 3306
Aplicación ContaPyme mostrando la tabla de terceros y un mensaje verde de tercero creado
El resultado final. Listado de terceros con búsqueda, botones para editar y eliminar, y un mensaje que confirma cada operación.
Qué parte del CRUD hace cada ruta

/ lista y busca (Read). /nuevo crea (Create). /editar/5 actualiza el tercero 5 (Update). /eliminar/5 lo borra (Delete).

Dónde puede vivir esta aplicación

Flask necesita un programa de Python encendido todo el tiempo. En tu computador funciona perfecto. En un hosting compartido que solo ejecuta PHP no se puede publicar así: ahí se usa la estrategia A o B del laboratorio 3.

Paso 1. Prepara las herramientas

Comprueba que tienes estas tres cosas antes de seguir:

  • Python 3.10 o superior. Abre la terminal (Win y escribe cmd) y ejecuta python --version. Si Windows abre la tienda o dice que no encuentra el comando, reinstala Python marcando Add python.exe to PATH.
  • VS Code con la extensión Python de Microsoft. En VS Code: Ctrl+Shift+X, busca Python e instala la de Microsoft.
  • WampServer instalado. Trae Apache, PHP, MySQL, MariaDB y phpMyAdmin.
VS Code con la extensión Python instalada
Extensión Python en VS Code. Debe decir Microsoft como publicador y tener el botón Desinstalar, señal de que ya está instalada.

Paso 2. Enciende WampServer

  1. Abre WampServer desde el menú Inicio y espera a que aparezca su ícono junto al reloj.
  2. El color del ícono indica el estado: verde, todo encendido; naranja, algún servicio no arrancó; rojo, ninguno.
  3. Haz clic izquierdo en el ícono. Verás el menú de la imagen. Fíjate en la línea Default DBMS: mysql: significa que MySQL es el motor principal.
Menú de WampServer 3.3.7 con PhpMyAdmin, Apache 2.4.62, PHP 8.3.14, MySQL 9.1.0 y MariaDB 11.5.2
Menú de WampServer. Versión 3.3.7 con MySQL 9.1.0 y MariaDB 11.5.2. Desde aquí se abre phpMyAdmin.
MySQL y MariaDB no son la misma base

WampServer trae los dos motores. MySQL usa el puerto 3306 y MariaDB el 3307. Si creas la base en uno y el programa se conecta al otro, aparece el error Unknown database. En este taller todo va en MySQL, puerto 3306.

Si el ícono queda naranja

Casi siempre es Apache, porque otro programa ocupa el puerto 80. Apache solo hace falta para phpMyAdmin; Flask no lo usa. Clic izquierdo, Apache, Service administration, Test port 80 te dice qué programa lo está usando.

Paso 3. Entra a phpMyAdmin

  1. En el menú de WampServer, elige PhpMyAdmin, o abre http://localhost/phpmyadmin en el navegador.
  2. Usuario root, contraseña vacía y, en Elección del servidor, MySQL.
  3. Al entrar, revisa el panel derecho: debe decir Servidor: MySQL (127.0.0.1 via TCP/IP) y el usuario root@localhost.
Pantalla principal de phpMyAdmin conectada al servidor MySQL 9.1.0 en el puerto 3306 con el usuario root
phpMyAdmin conectado. Arriba dice Servidor: MySQL:3306. A la derecha: MySQL 9.1.0, usuario root@localhost, juego de caracteres utf8mb4. Esos son los datos que usará tu programa.
root sin contraseña solo en tu equipo

Es la configuración de fábrica de WampServer y sirve para aprender. Un servidor real nunca se deja así: allí se crea un usuario propio para la aplicación, con contraseña y solo los permisos que necesita.

Paso 4. Crea la base de datos y la tabla

  1. En phpMyAdmin, pestaña SQL (arriba).
  2. Pega el script completo y pulsa Continuar, abajo a la derecha.
  3. Recarga la página. En el panel izquierdo aparece contapyme_flask; ábrela, entra a terceros y pulsa Examinar. Deben verse tres registros.

Qué hace cada parte: utf8mb4 guarda tildes, eñes y emojis sin dañarlos. AUTO_INCREMENT numera cada tercero solo. UNIQUE en el NIT impide registrar dos veces la misma empresa: es MySQL quien protege el dato, aunque el programa tenga un error. ENUM solo acepta cliente o proveedor.

Pestaña SQL de phpMyAdmin con el script pegado
Script pegado en la pestaña SQL. El botón Continuar queda abajo a la derecha.
Tabla terceros con tres registros
La tabla con los datos de ejemplo. Si ves tres filas, la base está lista.

Paso 5. Crea el proyecto en VS Code

  1. Crea una carpeta sin espacios ni tildes en la ruta, por ejemplo C:\proyectos\contapyme-flask.
  2. En VS Code: Archivo, Abrir carpeta, elige esa carpeta y acepta Sí, confío en los autores.
  3. Crea esta estructura con los íconos de Nuevo archivo y Nueva carpeta del explorador. Los nombres templates y static son obligatorios: Flask los busca exactamente así.
Explorador de VS Code con la estructura del proyecto
Estructura en VS Code. Las carpetas templates y static deben estar al mismo nivel que app.py, no dentro de otra carpeta.

Paso 6. Entorno virtual e instalación

Un entorno virtual es una copia de Python solo para este proyecto. Así las librerías de un proyecto no chocan con las de otro.

  1. Abre la terminal de VS Code: Terminal, Nueva terminal (o Ctrl+ñ).
  2. Crea el entorno, actívalo e instala las librerías:

El archivo requirements.txt contiene:

  1. Si todo salió bien, la línea de la terminal empieza con (venv).
  2. Presiona Ctrl+Shift+P, escribe Python: Select Interpreter y elige el que dice venv. Así VS Code deja de subrayar flask como si no existiera.
Error: "la ejecución de scripts está deshabilitada en este sistema"

PowerShell bloquea el script que activa el entorno. Ejecuta una sola vez Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, confirma con S y vuelve a activar. Si el equipo es de la sala y no lo permite, cambia la terminal a Command Prompt con la flecha junto al + de la terminal.

Terminal de VS Code con el entorno virtual activo
Entorno activo e instalación terminada. Busca (venv) al inicio y Successfully installed al final.

Paso 7. La conexión: db.py

Este archivo tiene una sola tarea: abrir conexiones a MySQL. Separarlo de las rutas es la misma idea de capas del laboratorio 3: si mañana cambias de base de datos, solo tocas este archivo.

os.getenv("DB_PASSWORD", "") busca una variable de entorno y, si no existe, usa el valor de la derecha. Con WampServer de fábrica no tienes que cambiar nada. Si tu MySQL tiene contraseña, la defines en la terminal en vez de escribirla en el código, y así no terminas subiéndola a GitHub:

Paso 8. app.py: la aplicación y la validación

Empieza app.py con lo que usan todas las rutas: las importaciones, el objeto app y una función que lee y valida el formulario.

Flask(__name__) crea la aplicación. secret_key es necesaria para los mensajes flash, esos avisos verdes y rojos que aparecen una sola vez después de guardar. leer_formulario devuelve los datos limpios y una lista de errores; si la lista está vacía, los datos son válidos.

Comparado con Java

En Java harías una clase con @RestController o un Servlet con doGet y doPost. En Flask, una función con el decorador @app.route cumple ese papel.

Paso 9. Leer: listar y buscar (R)

Mira los %s: son los huecos donde mysql-connector pone los valores de forma segura. Nunca armes la consulta pegando texto con f"...{q}...", porque eso abre la puerta a la inyección SQL que viste en el laboratorio 3. dictionary=True hace que cada fila llegue como diccionario, así en la plantilla escribes t.nombre en vez de t[2]. El bloque try/finally garantiza que la conexión se cierra aunque ocurra un error.

Ahora las dos plantillas que usa esta ruta. base.html es el molde común; las demás páginas lo heredan con extends y solo llenan el bloque contenido.

Y la hoja de estilos, para que se vea como en los pantallazos:

Paso 10. Crear (C)

La misma ruta atiende dos momentos: con GET muestra el formulario vacío, con POST recibe lo que el usuario escribió.

con.commit() confirma el cambio: sin esa línea el registro no se guarda. Si MySQL rechaza el NIT porque ya existe, lanza el error 1062 (ER_DUP_ENTRY) y lo convertimos en un mensaje comprensible. Después de guardar se redirige al listado; así, si el usuario recarga la página, no se crea el registro dos veces.

El formulario sirve para crear y para editar. Si recibe un tercero, muestra sus datos; si no, aparece vacío.

Paso 11. Actualizar (U)

<int:id_tercero> toma el número de la dirección: en /editar/2, id_tercero vale 2. Si ese tercero no existe, abort(404) responde "no encontrado" en vez de fallar. Fíjate en el WHERE id=%s del UPDATE: sin él, se modificarían todos los terceros de la tabla.

Paso 12. Eliminar (D) y arrancar la aplicación

Eliminar solo acepta POST. Si fuera un enlace normal (GET), bastaría con abrir una dirección, o que el navegador la precargara, para borrar datos. Por eso en index.html el botón está dentro de un formulario y pide confirmación.

debug=True recarga la aplicación cada vez que guardas un archivo y muestra los errores con detalle. Sirve para desarrollar; en un servidor público se apaga.

Paso 13. Ejecuta y prueba

  1. Con (venv) activo, ejecuta python app.py.
  2. La terminal muestra Running on http://127.0.0.1:5000. Mantén Ctrl y haz clic en la dirección.
  3. Prueba las cuatro operaciones en este orden: busca "pap", crea un tercero, intenta crear otro con el mismo NIT, edita uno y elimina otro.
  4. Para detener el servidor: Ctrl+C en la terminal.
Terminal con el servidor Flask en ejecución
Servidor encendido. Mientras esta terminal esté abierta, la aplicación responde.
Listado de terceros con buscador, botones Editar y Eliminar
Read. Los tres terceros del script, ordenados por nombre.
Formulario de nuevo tercero diligenciado
Create. Formulario diligenciado antes de pulsar Guardar.
Formulario con el mensaje rojo Ya existe un tercero con ese NIT
Validación. MySQL rechazó el NIT repetido y la aplicación lo explica sin perder lo que el usuario escribió.

Paso 14. Comprueba en phpMyAdmin

La prueba definitiva de que el CRUD funciona no es la página web: es la base de datos. Vuelve a phpMyAdmin, abre terceros y pulsa Examinar. El tercero que creaste debe estar allí, con su id y la fecha en creado; el que eliminaste ya no.

Tabla terceros en phpMyAdmin con el registro nuevo
El dato llegó a MySQL. La misma fila que ves en la aplicación, ahora en la tabla.

Errores frecuentes y su solución

MensajeCausa probableSolución
ModuleNotFoundError: No module named 'flask'El entorno virtual no está activo o VS Code usa otro intérprete.Activa venv (paso 6) y elige su intérprete.
2003: Can't connect to MySQL serverWampServer apagado o MySQL detenido.Ícono en verde; clic izquierdo, MySQL, Start service.
1049: Unknown database 'contapyme_flask'No ejecutaste el script, o lo ejecutaste en MariaDB.Repite el paso 4 con el servidor MySQL seleccionado.
1045: Access denied for user 'root'Tu root sí tiene contraseña.Defínela con $env:DB_PASSWORD (paso 7).
TemplateNotFound: index.htmlLa carpeta no se llama templates o está en otro nivel.Revisa la estructura del paso 5.
El formulario no cambia de aparienciaEl navegador guardó la versión vieja del CSS.Ctrl+F5 para recargar sin caché.
Address already in use o el puerto 5000 ocupadoOtra ejecución de la aplicación sigue abierta.Cierra la otra terminal o usa app.run(debug=True, port=5001).

Reto y entregable

Reto: agrega el campo ciudad a los terceros. Debe guardarse, mostrarse en el listado y poder editarse. Toca las cuatro capas:

  1. Base de datos: en phpMyAdmin, ALTER TABLE terceros ADD ciudad VARCHAR(60) NULL;
  2. Validación: agrega "ciudad" al diccionario de leer_formulario.
  3. Consultas: incluye la columna en el INSERT y en el UPDATE, con su %s y su valor en la tupla.
  4. Plantillas: un campo nuevo en formulario.html y una columna nueva en index.html.

Entrega: la carpeta del proyecto comprimida sin la carpeta venv (pesa mucho y se reconstruye con requirements.txt), más un documento con los pantallazos de los pasos 4, 6, 13 y 14 y de la ciudad funcionando.

CriterioSuperiorAltoBásicoBajo
CRUD funcionandoLas cuatro operaciones y la búsqueda funcionanLas cuatro operaciones funcionanFuncionan listar y crearNo se conecta a la base
Reto ciudadCompleto en las cuatro capasFunciona con un detalle pendienteSolo en la base o solo en la vistaNo lo intentó
Seguridad y calidadConsultas con %s, eliminar por POST, errores manejadosConsultas con %sMezcla consultas seguras e insegurasConcatena texto en el SQL
EvidenciasPantallazos completos y explicadosPantallazos completosFaltan algunosSin evidencias
El reto de la ciudad es también la prueba de sustentación: pídele al estudiante que agregue en vivo un campo distinto, por ejemplo direccion. Quien entendió las cuatro capas lo resuelve en minutos; quien copió el proyecto no sabe por dónde empezar. Revisa además que no entregue la carpeta venv ni contraseñas escritas en db.py.