Ir al contenido principal

Últimos 2 días de trabajo

Los últimos 2 días de trabajo, correspondientes al jueves 15 y viernes 16, fueron los días mas productivos que hemos tenido.

La pagina web fue finalizada su totalidad, esto correspone a cambios esteticos minimos y la creacion de un menú de ajustes, se creó la BD con sus respectivas tablas, y se hicieron los stored procedures para conectar todo, además se finalizó el parseo de los archivos xml.

Respecto a la creación de los procedures para hacer los CRUD, no hubo muchas complicaciones, como ya antes habíamos hecho pruebas con una Bd de prueba, crear las versiones finales de los procedures se redujo a simplemente crearlos siguiendo la plantilla dada por el profesor, e ir modificándolos según cada tabla. se puede ver nuestro repositorio de GitHub para notar que prácticamente ya son creadas en sus versiones finales, y son modificadas solo para hacer correcciones menores.

La lectura de los xml si tuvo varios problemas, si bien la version creada pot el compañero era perfectamente funcional, personalmente no me gustaba que el path a el xml debía modificarse del procedure cada vez que se debía ejecutar, es decir, que el procedure solo serviría en una computadora y en un archivo en un directorio especifico, y en caso de querer hacerlo en otro lugar, habría que modificarlo.

Por eso mismo yo tomé la misión de investigar sobre como hacer que el path se diera como una variable al llamar al procedure, esto no fue algo sencillo, principalmente por que habría que hacer una linea de Código de forma dinámica, investigando encontré los siguientes materiales:

https://www.youtube.com/watch?v=ByzqtSep8G0

En dicho video explican como crear dicha linea de código de forma dinámica y como ejecutarla, mi problema es que si bien eso ayudaba, al estar trabajando con xmls no era tan sencillo como el video mostraba, luego de trabajar un tiempo llegue tener una version en donde no daba errores, pero las tablas no eran modificadas, como si el xml nunca fuera cargado, investigando encontré que la razón era que la variable con el xml que era creada de forma dinámica, era eliminada justo después de haber ejecutado el programa, al parecer el código que se ejecuta de eat forma esta encapsulado dentro de si mismo, como si fuera un procedure distinto.

Con esto pensé que la solución lógica sería hacer que hubiera un valor de salida, y obtenerlo, y para eso use el siguiente material:

https://stackoverflow.com/questions/803211/how-to-get-sp-executesql-result-into-a-variable


Con esto obtenía el xml parseado desde el output del xml creado de forma dinámica. y finalmente se logró parsear el xml, llenar las tablas, y tener todo el trabajo prácticamente terminado, el codigo final de la carga se ve de esta forma:

CREATE PROCEDURE dbo.CargarXML
    -- Parametro de entrada
    @inRutaXML NVARCHAR(500)
AS

DECLARE @Datos xml/*Declaramos la variable Datos como un tipo XML*/

DECLARE @outDatos xml -- parametro de salida del sql dinamico

 -- Para cargar el archivo con una variable, CHAR(39) con comillas simples
DECLARE @Comando NVARCHAR(500)= 'SELECT @Datos = D FROM OPENROWSET (BULK '  + CHAR(39+ @inRutaXML + CHAR(39+ ', SINGLE_BLOB) AS Datos(D)'
DECLARE @Parametros NVARCHAR(500)
SET @Parametros = N'@Datos xml OUTPUT'

EXECUTE sp_executesql @Comando, @Parametros, @Datos = @outDatos OUTPUT

SET @Datos = @outDatos
    
DECLARE @hdoc int /*Creamos hdoc que va a ser un identificador*/
    
EXEC sp_xml_preparedocument @hdoc OUTPUT, @Datos/*Toma el identificador y a la variable con el documento y las asocia*/


INSERT INTO [dbo].[TipoDocIdent]
           ([ID]
           ,[Nombre])/*Inserta en la tabla TipoDocIdent*/
SELECT *
FROM OPENXML (@hdoc, '/Datos/Catalogos/Tipos_de_Documento_de_Identificacion/TipoIdDoc' , 1)/*Lee los contenidos del XML y para eso necesita un identificador,el 
PATH del nodo y el 1 que sirve para retornar solo atributos*/
WITH(/*Dentro del WITH se pone el nombre y el tipo de los atributos a retornar*/
    Id int,
    Nombre VARCHAR(20)
    )


INSERT INTO dbo.Puestos
                ([ID]
               ,[Nombre]
               ,[SalarioXHora])/*Inserta en la tabla Puestos*/
SELECT *
FROM OPENXML (@hdoc, '/Datos/Catalogos/Puestos/Puesto' , 1)/*Lee los contenidos del XML y para eso necesita un identificador,el PATH del nodo y el 1 que sirve 
para retornar solo atributos*/
WITH(/*Dentro del WITH se pone el nombre y el tipo de los atributos a retornar*/
    Id int,
    Nombre VARCHAR(50),
    SalarioXHora money
    )


INSERT INTO [dbo].[Departamentos]
           ([ID]
           ,[Nombre])/*Inserta en la tabla Departamentos*/
SELECT *
FROM OPENXML (@hdoc, '/Datos/Catalogos/Departamentos/Departamento' , 1)/*Lee los contenidos del XML y para eso necesita un identificador,el PATH del nodo y el 
1 que sirve para retornar solo atributos*/
WITH(/*Dentro del WITH se pone el nombre y el tipo de los atributos a retornar*/
    Id int,
    Nombre VARCHAR(50)
    )
    
    
DELETE FROM dbo.Empleados/*Limpia la tabla empelados*/
DBCC CHECKIDENT ('Empleados', RESEED, 1)/*Reinicia el identify*/

INSERT INTO [dbo].[Empleados]
           ([Nombre]
           ,[IdTipoIdentificacion]
           ,[ValorDocumentoIdentificacion]
           ,[IdDepartamento]
           ,[IdPuesto]
           ,[FechaNacimiento])/*Inserta en la tabla Empleados*/
SELECT *
FROM OPENXML (@hdoc, '/Datos/Empleados/Empleado' , 1)/*Lee los contenidos del XML y para eso necesita un identificador,el PATH del nodo y el 1 que sirve
para retornar solo atributos*/
WITH(/*Dentro del WITH se pone el nombre y el tipo de los atributos a retornar*/
    Nombre VARCHAR(100),
    idTipoDocumentacionIdentidad int,
    ValorDocumentoIdentidad VARCHAR(10),
    IdDepartamento int,
    idPuesto int,
    FechaNacimiento date
    )


 

INSERT INTO [dbo].[Administradores]
           ([Usuario]
           ,[Contrasena]
           ,[Tipo])/*Inserta en la tabla Administradores*/
SELECT *
FROM OPENXML (@hdoc, '/Datos/Usuarios/Usuario' , 1)/*Lee los contenidos del XML y para eso necesita un identificador,el PATH del nodo y el 1 que sirve
para retornar solo atributos*/
WITH(/*Dentro del WITH se pone el nombre y el tipo de los atributos a retornar*/
    username VARCHAR(50),
    pwd VARCHAR(50),
    tipo INT
    )
    
EXEC sp_xml_removedocument @hdoc/*Remueve el documento XML de la memoria*/

Pero de nuevo pensé, que si bien ya no había que modificar el código cada vez que se introducía un archivo distinto, no era muy amigable con el usuario pedirle la ruta a un archivo, por lo que decidí ponerme a implementar una forma de cargar los xml desde la pagina web, primero usé estos tutoriales para recibir los archivos:


https://blog.miguelgrinberg.com/post/handling-file-uploads-with-flask

https://stackoverflow.com/questions/82831/how-do-i-check-whether-a-file-exists-without-exceptions

Y luego desde el código, solamente le enviaba la ruta del archivo que se acaba de subir, al procedure que carga los xml, de esta forma la carga de los XML, que ya funcionaba desde un inicio, fue implementada de una forma mas elegante. (aunque aún así yo hubiera implementado el parse de una forma distinta, en vez de cargarlos en SQL, yo hubiera cargado el archivo en capa lógica y desde ahí enviar los tuplos a la base de datos, de forma similar a como funciona el insertar en la pagina web)

Código final para la carga de archivos desde la pagina:


uploaded_file = request.files['xml']

filename = secure_filename(uploaded_file.filename)
if filename != '':
    file_ext = os.path.splitext(filename)[1]
    if file_ext not in app.config['UPLOAD_EXTENSIONS']:
        flash("Archivo no valido""error")
        redirect(url_for("ajustes")) 
    
    p = os.path.join(app.config['UPLOAD_PATH'], filename)
    num = 2
    #verificamos que no haya un archivo con el mismo nombre, si no lo modificamos
    while os.path.exists(p):
        newfilename = str(num) + filename
        p = os.path.join(app.config['UPLOAD_PATH'], newfilename)
        num += 1
    uploaded_file.save(p) #guardamos el archivo
    
    #obtenemos la ruta del archivo en el directorio
    ruta_del_archivo = os.path.dirname(os.path.realpath(__file__)) + "\\" + p
    ruta_del_archivo = str(ruta_del_archivo)
    #llamamos al stored procedure
    Logic.cargar_xml(ruta_del_archivo)


El día siguiente cuando nos dieron la version final de los catálogos en xml, hubo que modificar un poco el código, tuvimos que eliminar algunas columnas que iban a quedarse sin usar,  (por lo tanto modificar los procedures) y modificar la carga del xml debido a que la estructura de los nodos era distinta a como estaba en el ejemplo, pero luego de trabajar en esto, y hacer unos cambios mínimos en la pagina web, se dió por terminado el trabajo.


-  Oswaldo (aprox 8 horas entre los 2 dias) 






Comentarios

Entradas populares de este blog

TAREA 3

Cantidad de horas trabajadas: Oswaldo: 26 Jenaro: 26 Debido a la elaboración de la tercera tarea programada podemos concluir que: Se tiene un mejor conocimiento y una mejor practica en la elaboración de una base de datos Aprendimos sobre leer archivos XML en SQL Server y como añadir los datos del XML a las tablas respectivas de la base de datos, sobre como modificar estos archivos, y como "jugar" con estos Se instruyo  la elaboración de una pagina web utilizando HTML y Python, usando la librería de Flask y el framework de Bootstrap y conectar la pagina web con la base de datos para poder añadir, editar, buscar y eliminar datos en la página web y que estos procesos se reflejen en la base de datos Se tiene un mejor conocimiento en la creación de vistas, manejo de errores y uso de transacciones Análisis de resultados: En general nos sentimos bastante orgullosos del trabajo realizado, tanto en la pagina como en la base de datos implementamos todas las funcionalidades, el programa...

Casi Finalización de la Pagina Web y Placeholders para Conexión con la BD

Esta ultima semana fue dedicada a la casi completa finalización de la pagina web del sistema de administración, todas las partes que faltaban de implementar están listas, además se realizo una conexión con la parte de datos de forma provisional, a continuación se hace un resumen de lo realizado: La opción de listar empleados  fue mejorada con iconos para editar y eliminar, aunque de momento debido al no tener una BD real estos no hacen nada. Edición de empleado y puesto fue mejorada drásticamente, con sus datos tomados de un catalogo y siendo mostrados en forma de drop menu, además la inserción de la fecha de nacimiento se hace mediante un calendario, por lo que de esta forma es imposible que se inserten datos no validos o en el formato incorrecto. Respecto a lo que mencioné anteriormente de los iconos de editar y borrar, hay una implementación básica realizada: En la lista de puestos si se seleccionan estos iconos, nos en...