Creación de HTML index, modificación de SP, modificaciones en el controlador, entre otros.

Fecha: Domingo 22 de marzo 2026

Hora de inicio: 8:00 a.m. (aproximadamente)

Hora de Finalización: 5:10 p.m. 

Hora de inicio: 7:40 p.m.

Hora de Finalización: 9:00 p.m.

Total de horas trabajadas:  10 h 30 min

*Nota: Esta bitácora se está realizando el día 23/03/26, porque el día de las actividades realizadas me encontraba muy cansada para realizar la bitácora. Los movimientos en el repositorio comprueban que el trabajo realizado corresponde al día 22/03/26.*

La idea de esta sesión era terminar la parte programada que quedaba. El plan inicial era crear los html correspondientes y terminar de conectarlos con el modelo por medio del controlador, sin embargo, terminamos modificando partes que anteriormente creíamos completadas debido a que en un inicio se nos complicó no usar SQL incrustado. 

Actividades Realizadas

8:00 a.m. - 12:00 m.d.

Durante este lapso me encargué principalmente de investigar todo lo relacionado con el desarrollo de páginas web, ya que era un área bastante nueva para mí, antes de esta tarea, solo había visto información muy superficial sobre el tema, y antes de este lapso mi mayor fuente de información sobre el tema fueron algunos videos que vi el día anterior, que mencionaban esta área pero no era mi foco de atención cuando los vi, por lo que fue necesario dedicar un tiempo prudente a la investigación. 

Empecé investigando qué es HTML y cómo funciona su estructura básica. Aprendí que no es un lenguaje de programación sino un lenguaje de marcado, donde cada elemento se define con etiquetas de apertura y cierre. Luego investigué CSS, que es el lenguaje que define el aspecto visual de la página, colores, tamaños, espaciado, etc. Como no íbamos a escribir CSS desde cero, investigué  más a fondo Bootstrap, que es una librería CSS que provee clases predefinidas para hacer páginas con diseño bonito sin necesidad de escribir estilos manualmente. Más adelante (cuando ya estaba diseñando el HTML) descubrí que se puede implentar mediante CDN, o sea, un link en el HTML que carga la librería desde internet sin necesidad de descargar nada, al final esto fue lo que terminamos usando en esa parte.

También investigué las bases de Jinja2, que es el motor de templates de Flask. Era importante tener presente Jinja 2 porque es lo que nos permite implementar código de Python en html, usando {{variabe}}  y {% for %} sobre todo. Lo anterior era necesario para que en la página se mostraran los empleados.

Si debo resumir lo que hice durante este proceso sería:

  • Investigar bases de HTML
  • Investigar bases de CSS (boostrap y Style)
  • Bases de Jinja2 (no ocupaba un conocimiento muy avanzado, solo lo más básico)
También debo mencionar que, aproximadamente a las 9:30 a.m. de este día continué la conversación con el profesor sobre el diagrama de arquitectura de aplicación que yo había hecho. Lo menciono de manera breve porque en realidad él en un audio anterior ya lo había aprobado pero yo no entendí bien y se continúo la conversación hasta que él me mencionó el hecho de que ya lo había aprobado.

Durante este lapso realmente no tuve muchos problemas, pues fue un proceso prácticamente 100% investigativo que no se da tanto para errores.

12:00 m.d. - 5:10 p.m.

En este lapso se hicieron una serie de cosas variadas, que no tienen un tiempo específico más allá de saber que se hicieron durante este lapso, voy a enumerarlas lo mejor posible para llevar orden.

1) Hacer pull para recibir las actualizaciones que hizo mi compañera

El día anterior no había hecho pull de las actualizaciones que hizo mi compañera (que en su mayoría abarcaban el modelo -MVC-). 

Luego de esto hice mi propio Config.py. El config.py es un archivo que contiene los datos de conexión a la base de datos, por eso mismo es algo que no debe subirse en circunstancias normales al repositorio porque son datos sensibles. Más adelante me di cuenta que en el primer commit que hice en el día por razón de que olvidé agreglarlo al gitignore, el config.py sí se subió al repositorio. Posterior a eso lo borré del repositorio, sin embargo, como es un control de versiones, pues todavía quedan residuos mi config.py en el repositorio, esto sirve como lección para no volver a hacer algo similar por descuido.

Posterior a crear el config.py, volví a hacer pull porque había unas actualizaciones que mi compañera había hecho y que aún yo no tenía. Me di cuenta de esto porque al realizar la prueba de empleado_model me aparecía lo siguiente:
     Img 1: Error al ejecutar la prueba de empleado_model

Para ese punto el método para obtener empleados ya funcionaba (lo sabía por conversaciones con VB), entonces allí me di cuenta que tenía una versión desactualizada e hice pull para remediarlo.

Por motivos de qué el método para insertar empleados aún no era funcional, decidimos hacer un pequeño cambio en la repartición para que yo (JJ) pudiera avanzar sin necesidad de esperar a que VB terminara la subrutina. Por esto, ahora yo me iba a encargar del html index y ella del html de ingresar. Y así lo hicimos

2) Creación del html index

Dado lo mencionado anteriormente me dediqué durante una buena parte del tiempo a la creación del html. Como en la mañana había investigado bastante sobre el tema, realmente la creación del html no tomó tanto tiempo como pensaba en un inicio.

Este archivo es parte de la Vista en el patrón MVC y es la página principal de la aplicación, la primera que ve el usuario al abrir la app. Aquí utilicé los conocimientos reunidos en horas tempranas, es un archivo de casi 100 líneas, pero realmente teniendo noción básica de html, CSS y Jinja2 es muy fácil de comprender, así que voy a mencionar generalidades del archivo.

Antes que nada le agregué al método del controller encargado de hacer la conexión entre el modelo y la vista la llamada a la función obtener_empleados(), esto para poder hacer las revisiones al html de manera más sencilla.
   Img 2: agregar al método index() la llamada a al función obtener_empleados()

Bootstrap via CDN 

    Img3: boostrap vía CDF

Se cargó Bootstrap desde internet mediante un link. Esto evita tener que descargar nada y con solo agregar clases a los elementos HTML, Bootstrap aplica estilos automáticamente.

Estilos con <style>

                                       Img4: estilos propios

En un inicio no usé style, pero dado que en realidad es bastante fácil de implementar y que la diferencia era muy notoria con o sin, decidí implementarlo.

Los estilos propios se agregaron después del link de Bootstrap, importante para que los estilos propios se implementen en vez de los de Bootstrap. Se definió colores para el fondo, el navbar, etc. Además, se definió el estilo de letra.

Tabla de scroll

    Img5: Código para Scrollbar

La tabla se envolvió en un div con altura y un scroll (vertical) para que no se muestren todos los empleados de golpe.

For implementado con Jinja2

                              Img6: for de python implementado con Jinja2

Es una de las partes más importantes, porque básicamente es lo que permite que los empleados se reflejen en la página. El for recorre la lista de empleados que envía Flask desde el controller, y por cada uno genera una fila (id, nombre, salario).

Botón de insertar

    Img7: Implementación del botón para insertar

Este botón redirige a /insertar usando <a>. Al darle click el usuario es llevado al formulario de inserción (en un principio no hacía nada porque aún no se había creado dicho formulario, pero una vez se creó funcionó a la perfección).

Con eso considero está bien representado los aspectos más importantes de lo que hice en este lapso (importante mencionar que después me di cuenta que no implementé en el código de html la parte para que se mostrara el flask en esa página, por lo que tuve que actualizarlo después).

Una vez logrado, lo que yo pensaba, el index.html completo, primero hice pull, para traerme las actualizaciones de mi compañera en el método de insertar_empleados() del empleado_model. Luego hice commit y push al repositorio con las actualizaciones.

Después de hacer pull, volví a ejecutar el .py de pruebas y verifiqué que ya funcionaba también el método de insertar. Sin embargo, hablando con VB, coincidimos que no era buena idea dejar el SQL incrustado que fue necesario para hacer funcionar el método sin modificar nuevamente el Stored Procedure de inserción. Por ello, en lo que VB se encargaba de la creación del insertar_empleado.html yo me encargué de arreglar esa parte del modelo en la que ocupábamos SQL incrustado.

Estuve por un tiempo investigando en distintas fuentes hasta que me encontré con la siguiente información de github: Llamando a procedimientos almacenados · Wiki de mkleehammer/pyodbc

Allí se menciona que Pyodbc no maneja bien los parámetros de salida de un SP. En ese misma información mencionan como posible solución el uso de un bloque de código anónimo para resolver el problema, que fue la solución que VB implementó anteriormente, sin embargo, como acordamos, era una solución que no nos convenía ya que debíamos hacer uso de SQL incrustado, por ello negamos de esa solución. La buena noticia es que, una vez sabido que Pyodbc tenía este incoveniente, fue más fácil encontrar una solución que no requería SQL incrustado.

 El problema radicaba en cómo estaba definido el SP de inserción: el parámetro @resul estaba declarado como OUTPUT en la firma del SP, lo que significa que quien llama al SP es responsable de pasarlo y recibirlo. Pyodbc no es capaz de manejar este tipo de parámetros correctamente con la sintaxis CALL, por lo que fallaba al intentar invocar el SP.
                                       Img8:Muestra a @resul declarado como Output

La solución fue modificar el SP para eliminar @resul de la firma y declararlo internamente co. De esta manera, deja de ser un parámetro externo y se convierte en una variable local del SP, por lo que Python no necesita conocerla ni manejarla (O sea, Pyodbc no debe tratar directamente con ella). Para comunicar el resultado hacia afuera, el SP utiliza un SELECT @resul al final, que Python puede leer normalmente con fetchone() como si fuera cualquier consulta que retorna datos.

                               Img9: @resul declarado como variable locarl

Adicionalmente, fue necesario agregar SET NOCOUNT ON al inicio del SP. 

                      Img10: El error que se presenta sin SET NOCOUNT ON

Esto se debe a que cuando Python llama al SP, SQL Server manda dos cosas en secuencia: primero un mensaje interno indicando cuántas filas fueron afectadas por el INSERT, y luego el resultado del SELECT @resul. Pyodbc leía esa secuencia en orden y agarra el primer resultado que encuentra, que era el mensaje del INSERT y no el SELECT resul. Con SET NOCOUNT ON se le indica a SQL Server que no mande esos mensajes de filas afectadas, por lo que el único resultado que llega a Python es el SELECT @resul, que es el que realmente se necesita leer.

Con esos cambios en el SP, la llamada desde Python quedó sin SQL incrustado, utilizando únicamente la sintaxis CALL con los dos parámetros de entrada.

                                       Img11: insertar_empleado antes de los cambios

                                           Img12: insertar_empleado después de los cambios

Después de que terminé de hacer los cambios, hice commit y push.

7:40 p.m. - 9:00 p.m

Durante este lapso se hicieron las actualizaciones finales.

Primero hice pull para acceder al html que VB había creado y así conectarlo al controller haciendo un llamado a la función de insertar del modelo.
    Img13: Antes/Después de este fragmento del método insertar_empleado_post

Además de llamar a insertar_empleado(), también creé los mensajes Flash que debían mostrarse dependiendo el resultado obtenido.

Por último, modifiqué levemente index.html al darme cuenta (al ver el html que hizo VB y al probar la página) que no había agregado el código que permite mostrar el mensaje flash de éxito de inserción de un nuevo empleado.

                               Img14: código agregado a index.html

Luego de esto hice unas pruebas básicas de funcionamiento general y finalmente hice commit y push. Con esto en teoría la parte programada quedaba terminada.

Buenas prácticas descubiertas

  • Agregar archivos sensibles al gitignore antes de hacer el primer commit, no después. Una vez que un archivo se sube al repositorio, aunque se elimine después, queda registro de él en el historial de versiones.
  • Hacer pull antes de empezar a trabajar en cada sesión evita trabajar con versiones desactualizadas del código, como ocurrió en esta sesión donde al ejecutar las pruebas del modelo aparecían errores que ya habían sido corregidos por la compañera.
  • Cuando un método de la biblioteca que se está usando no soporta cierta funcionalidad, es mejor investigar una solución alternativa que mantenga las reglas del proyecto, en lugar de usar soluciones que las violen como SQL incrustado.
  • Hacer commit y push después de cada tarea completada, no acumular muchos cambios en un solo commit, facilita rastrear en qué punto se introdujo un error.

Consejos

  • Antes de elegir cómo llamar a un SP con parámetros OUTPUT desde Python, verificar si la biblioteca que se usa soporta ese tipo de parámetros. En el caso de pyodbc, no maneja bien los parámetros OUTPUT con la sintaxis CALL, por lo que la solución más limpia es declarar el parámetro de retorno como variable local dentro del SP y retornarlo con un SELECT al final.
  • Si al llamar un SP desde Python el resultado que se recibe no es el esperado, verificar si SQL Server está enviando mensajes adicionales antes del resultado real. Usar SET NOCOUNT ON al inicio del SP elimina esos mensajes y asegura que Python reciba únicamente el resultado que interesa.
  • Coordinar con el equipo antes de cambiar la firma de un SP, ya que eso afecta tanto el código SQL como el código Python que lo llama.

Referencias





Comentarios

Entradas más populares de este blog

Instalación del servidor

Configuración inicial: stack tecnológico, GitHub y estructura del proyecto

Creación de la base de datos y el primer stored procedure