Configuración del entorno virtual del proyecto Python y conexión a la base de datos

Fecha: sábado 21 de abril de 2026

Hora de inicio: 11:20 a.m.

Hora de finalización: 9:46 p.m.

Horas trabajadas: 6 h 28 min

El objetivo de esta sesión de trabajo fue configurar el entorno virtual, conectar la aplicación a la base de datos y tener el modelo funcionando para poder llamar a los stored procedures desde código. 

Actividades realizadas

11:20 a.m. – 12:08 p.m.: Corrección del SP dbo.ListarEmpleados

Antes de que empezara la reunión con Johana, aproveché para hacer mejoras al SP dbo.ListarEmpleados. Los cambios fueron dos, el primero fue renombrar el SP eliminando el prefijo sp_ para ser consistente con el nombre del SP de Johana, y el segundo fue agregar alias de tabla. Hice commit y push minutos después de que terminó la reunión que habíamos acordado, a las 12:38 p.m.

El cambio de nombre que realicé no fue solo por consistencia estética, pues encontré que Microsoft Learn advierte explícitamente que el prefijo sp_ está reservado para procedimientos del sistema de SQL Server, y usarlo en procedimientos propios puede causar conflictos si existe un procedimiento del sistema con el mismo nombre.

Antes de realizar estos cambios, también consulté al profesor por WhatsApp si debíamos utilizar alias de tabla en los SP y él confirmó que sí. Por otro lado, acerca de cuál estándar seguir para nombrar SPs, el profesor indicó que aun no ha establecido uno.
El antes y después del SP se puede ver en el repositorio, pero en resumen el cambio más visible fue este:

Antes:

CREATE PROCEDURE dbo.sp_ListarEmpleados
...
SELECT id, Nombre, Salario
FROM dbo.Empleado

Después:

CREATE PROCEDURE dbo.ListarEmpleados
...
SELECT E.id, E.Nombre, E.Salario
FROM dbo.Empleado AS E

También, recordé que había un archivo separado llamado sp_listar_empleados.sql que contenía la primera versión del SP, ya que cuando lo creé originalmente no recordaba que Johana ya había creado un archivo unificado para todos los SPs. Ella había copiado mi SP ahí y las modificaciones descritas anteriormente las realicé en ese mismo archivo, así que procedí a borrar el archivo con la versión desactualizada.

12:08 p.m. – 12:31 p.m.: Reunión de planificación por Teams

En esta reunión nos dividimos el trabajo de la aplicación de la siguiente manera, buscando que las dos participáramos en todas las capas:

Valeria (yo):

  • Configuración de conexión a la BD (config.py)
  • Llamadas a los SPs desde Python (modelo)
  • Pantalla principal con la tabla de empleados (vista/template)

Johana:

  • Rutas Flask (controlador)
  • Formulario de inserción (vista/template)
  • Punto de entrada de la aplicación
También le recordé a Johana que debía usar alias de tabla en el SP dbo.InsertarEmpleado.

3:15 p.m. – 4:54 p.m.: Configuración del entorno Python

Antes de empezar a programar, configuré el entorno.

Un tema que discutimos en la reunión fue cuál versión de Python teníamos, yo tenía instalada la versión 3.14.3, pero Johana la 3.13.12. Para garantizar compatibilidad entre los dos entornos, desinstalé la mía e instalé la misma versión que ella. Luego configuré VS Code para usar el nuevo intérprete.

Luego, creé el entorno virtual del proyecto. Al intentar activarlo en PowerShell, apareció este error:

Error al activar el entrono virtual

PowerShell tiene por defecto una política de seguridad llamada Restricted que bloquea todos los scripts locales.

La solución fue ejecutar:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Este comando lo encontré directamente en la documentación que sugería el mismo mensaje de error. Con eso el entorno virtual se activó sin problema.

Una vez activo el entorno, instalé las librerías y dependencias necesarias, en nuestro caso flask y pyodbc y generé el archivo requirements.txt. También instalé el ODBC Driver 17 for SQL Server desde la documentación oficial de Microsoft, este es necesario ya que actúa como traductor entre pyodbc y SQL Server.

6:20 p.m. – 6:47 p.m.: config.py y el .gitignore

Antes de crear el archivo config.py con la connection string para conectarse a SQL Server, verifiqué que estuviera en el .gitignore. No estaba, así que lo agregué. Esto es importante porque config.py contiene credenciales y no debe subirse al repositorio.

También le avisé a Johana que ella necesitaba tener su propia versión local de ese archivo con el IP de Hamachi de mi máquina, ya que el servidor de BD está en mi computadora.

Problema: un conflicto de merge

Al intentar hacer push del commit con las dependencias, Git no me dejó porque Johana había subido cambios al repositorio que yo no tenía. Git intentó hacer un merge automático y abrió Vim, un editor en la terminal que no reconocí.

Conflicto de merge

Solución:

Lo que hice fue buscar cómo salir de esa pantalla. Los pasos fueron:
  1. Presionar Esc
  2. Escribir :wq (que significa "write and quit")
  3. Presionar Enter

Con eso Git completó el merge automáticamente. Lo que no noté en ese momento fue que el merge había sobrescrito mis cambios en database/stored_procedures.sql con la versión anterior, porque Johana no había hecho pull antes de hacer push sobre ese mismo archivo. Me di cuenta de esto hasta el día siguiente. El conflicto real estaba en ese archivo y yo nunca lo revisé bien, pues pensé que se debía a que al no hacer pull antes de push, no tenía los archivos nuevos que Johana creó, no recordé que ella también tenía que modificar el archivo de los SPs, solo busqué salir de Vim y seguí.

7:00 p.m. – 9:46 p.m.: Conexión entre Python y los SPs

Esta fue la parte más pesada de la sesión. Primeramente, creé el archivo empleado_model.py dentro de app/models/. La idea del modelo es que una fila de la tabla Empleado en la base de datos se convierta en un objeto Python, así que definí la clase Empleado con los atributos id, nombre y salario.

Luego creé dos funciones: obtener_empleados() para llamar al SP dbo.ListarEmpleados, e insertar_empleado() para llamar a dbo.InsertarEmpleado.

Con las dos funciones listas, hice un archivo de prueba para verificar que funcionaran.

Script de prueba de las llamadas a los SPs desde Python

Problema:

Al ejecutar el archivo de prueba, las tres pruebas fallaron con el mismo error:

Error en la prueba del modelo

El problema estaba en cómo estaba manejando el parámetro OUTPUT del SP. La primera versión de las funciones usaba esto:

resultado = cursor.var(pyodbc.SQL_INTEGER)
cursor.execute("{CALL dbo.ListarEmpleados(?)}", resultado)

El método cursor.var() no existe en pyodbc. Existe en python-oracledb, que es el conector de Python para Oracle, no para SQL Server. Al buscar cómo manejar parámetros OUTPUT, el recurso más claro y detallado que encontré fue la documentación de python-oracledb. Sabía que era específico de Oracle, pero los conceptos parecían similares y la estructura del código se veía aplicable. Solo cuando ejecuté el código y vi el error me di cuenta de que aunque los conceptos son parecidos, las implementaciones son completamente diferentes entre una librería y otra.

La corrección para obtener_empleados() fue esta:

Antes

resultado = cursor.var(pyodbc.SQL_INTEGER)
resultado.setvalue(0, -2)
cursor.execute("{CALL dbo.ListarEmpleados (?)}", resultado)
...
return empleados, int(resultado.getvalue(0))

Después

parametros = [None]
cursor.execute("{CALL dbo.ListarEmpleados (?)}", parametros)
...
return empleados, resultado

Esto funciona porque dbo.ListarEmpleados tiene un SELECT interno que genera un recordset, y pyodbc actualiza automáticamente la lista con el valor del OUTPUT al procesarlo. Sin embargo, esta solución no funcionó para insertar_empleado(), porque dbo.InsertarEmpleado no tiene SELECT interno, solo hace un INSERT, y sin recordset, pyodbc nunca actualiza la lista. Eso me quedó pendiente de resolver.

Al final de la sesión, obtener_empleados() funciona correctamente:

Prueba obtener_empleados() funcionando bien

insertar_empleado() queda pendiente para la siguiente sesión.

Forma de trabajo del equipo

La planificación fue por Teams y la coordinación durante el trabajo por WhatsApp. Trabajamos en paralelo, cada una en su parte, aunque el conflicto de merge fue un recordatorio de que cuando dos personas tocan el mismo archivo hay que coordinarse mejor antes de hacer push.

Buenas prácticas descubiertas

  • Agregar al .gitignore cualquier archivo con credenciales antes de crearlo, no después.
  • Verificar siempre la documentación específica de la librería que se está usando, sin importar que algunos conceptos entre conectores de bases de datos puedan parecer similares, pues las implementaciones son distintas.
  • Hacer pull antes de push cuando se trabaja en equipo, especialmente si la otra persona también está trabajando en los mismos archivos.
  • Usar la misma versión de Python en todos los entornos del equipo desde el inicio para evitar problemas de compatibilidad.
  • No usar el prefijo sp_ en stored procedures propios en SQL Server.

Moraleja del día

Asumir que la documentación de una librería aplica a otra porque hacen lo mismo puede costar tiempo. Tanto pyodbc como python-oracledb conectan Python con bases de datos relacionales, pero son librerías distintas con implementaciones distintas. Siempre es mejor buscar la documentación específica de lo que se está usando, aunque la otra parezca más clara o completa.

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