Curso de programacion en python3 : 10 - Administrando una BD desde python

Esta entrada requiere conocimiento en DBA que he escrito aqui, y es parte del curso de python que empieza aquí

Hola buenas tardes, vengo bastante hater, tengo mas de cuatro días intentando que funcione pymysql y no voy a ser nada benevolente con la librería que tengo que usar, no hay otra librería y el equipo de mariadb desarrolla una que esta en beta, tiene todo el sentido del mundo que estén trabajando en una propia.

No hay documentación sobre pymysql, pregunté un asunto no trivial por medio de github puesto que no es normal el comportamiento que demostrada el modulo, puesto que no está escrito en la "documentación" del proyecto, lo único que han asociado es un ejemplo escueto de un caso concreto, el desarrollador en vez de decirme que podía ayudar a ampliar la documentación o simplemente aclarar las dos condiciones mutuamente excluyentes que causaban el problema, me dijo que buscara en google, claro que después de tres días de búsqueda intensiva donde no hay documentación y no hay un solo tema en la web que me permitiera asociar los dos errores estructurales, una escueta respuesta que no solucionó el problema y tampoco pretende mejorar en nada el proyecto, me resulta bastante decepcionante.

Luego de alterar mi código sin ningún sentido hasta encontrar la combinación de factores justa que me garantizó que el paquete esta mal enfocado y no cumple con la estandarizan mínima a la que me han acostumbrado los módulos de C, C++, Java y C#, puedo garantizar que la única forma de conectarse con bases de datos MySQL/MariaDB hasta la fecha deja mucho que desear, el proyecto existe desde 2009 y ha pasado por las manos de demasiados relevos sin intentos de bifurcar el proyecto y unificar su forma de trabajo, cuenta con 1.2K de bifurcaciones, he estado revisando el estado de las bifurcaciones y cada una es igual que la anterior, nadie ha intentado siquiera corregir lo mas básico del proyecto, mas que rabia es tristeza, por que los principales problemas son de documentación y errores de funcionamiento con respecto a las bases de datos.

Me documente bastante sobre las extensiones de conexión entre python y bases de datos, para mi primera sorpresa hay una implementación de SQLite preinstalada, es una especie de RDBMS(sistema de control de bases de datos relacionales) que funciona con archivos y no garantiza muchas cosas, pero es muy útil para mantener bases de datos en local sin obligar a que los usuarios instalen nada, para todas las otras bases de datos es necesario instalarlas, voy mas allá y apuesto que si no vamos a necesitar que los datos sean centralizados en un único servidor de bases de datos, lo mas coherente es utilizar SQLite, sobre todo en vista de los problemas que da pymysql.
  • Microsoft SQL Server: > pip install pyodbc
  • MySQL/MariaDB: > pip install pymysql
  • PostgreSQL: > pip install pygresql
Por estándar el proceso es similar, yo voy a usar MariaDB/MySQL y por tanto, solo estoy seguro que funciona para esos dos RDBMS, es necesario crear un usuario con solo los privilegios necesarios para que nuestra aplicación sea útil y las brechas de seguridad no existan, si existen, por lo menos no será culpa nuestra.

Si alguien ha decidido usar MariaDB y descargar phpMyAdmin, se dará cuenta que el gestor de bases de datos es una pagina web escrita en PHP que funciona para administrar bases de datos locales, esto para un sitio en linea es un peligro, con añadir phpMyAdmin al final de la url de un sitio web en internet a veces es posible encontrar la instancia y empezar a probar contraseñas, es un complemento útil que hay que esconder cuando se instala junto a un servidor web apache.

Por cuestiones de modularidad, es importante la división de todo proyecto en los trozos mas pequeños que podamos, un menor crecimiento de los archivos garantiza mas agilidad en la corrección de errores y simplicidad del código como conjunto.

El modulo Persona está en la carpeta modelo y solo es el marco que utilizamos para garantizar que los ingresos del usuario serán coherentes con lo que espera la base de datos, es importante recordar que los casos especiales no son suficientemente especiales para romper las reglas, los objetos de modelo tenemos que alterarlos usando sus métodos que están configurados, en las operaciones con persona veremos la vital importancia de esto para evitar problemas con los usuarios.

El único modulo que tendrá contacto directo con la db será ConectarConBaseDeDatos , se instancia pymysql con la etiqueta mariadb, como indicador de la base de datos a la cual el proyecto debe conectarse, recordemos que la palabra reservada "as" solamente nos permite colocar una etiqueta a la instancia, creo aquí tres métodos,  el main que lo utilizo para pruebas, haciendo separación entre cada modulo y sus dependencias, probando cada cosa de abajo a arriba(en orden de controlador, modelo y vista), un método para configurar una conexión personalizada, por que es una mala practica que el las configuraciones no sean alterables y un método de conexión, utiliza aquellos datos que podemos modificar con la configuración de conexión.

El puerto por defecto de las bases de datos es el 3306, mi usuario desechable es persona y su contraseña no es segura, tampoco importa en este caso por que todos los puertos de mi maquina están filtrados, no esta conectada a internet casi nunca y el servidor tengo que encenderlo manualmente con privilegios de administración, la base de datos será Universidad, el cursor es una estructura que apuntará a la base de datos y contiene las respuestas de la misma, cada cursor apuntará a un vector con los datos devueltos, ayudándonos a gestionar las cosas.

En el modulo OperacionesConPersonas tenemos las cuatro sentencias básicas(Select, Insert, Update, Delete), también las acciones que se repitan muchas veces deben convertirse en un método aparte, igual la conexión y el cursor deberían ser métodos dentro de ConectarConBaseDeDatos, el estrés de no conseguir que pymysql funcionara me llevó a muchos errores de reiteración de código.

Para insertar personas hay que construir un objeto del tipo Persona y luego enviarlo al método, se crea la instancia que contiene a la conexión con la base de datos, se crea una conexión, se crea un cursor, dejo una variable para contar las filas afectadas(esto me permite saber si la sentencia se ha ejecutado o no), hago un string de sql con la sentencia, se utiliza como guarda espacios al carácter %s donde el porcentaje es un espacio a rellenar y la letra implica que será un string, uno de los errores de pymysql es que los tipos int deben ser pasados como string, rompiendo la consistencia de datos, es ilegal enviar datos de tipos incorrectos y la librería nos obliga a esta mala practica, al ejecutar la sentencia en el cursor tenemos que enviar por parámetro una tupla(por que está entre paréntesis y separada por comas) que contenga los datos de la persona, si no hay error en esto, en la conexión se ejecuta el commit(una confirmación de cambios implica que estamos de acuerdo con los cambios realizados y deseamos que se escriban en el disco duro, los cambios no confirmados serán desechados) y se cierra la conexión.

Si saltase una excepción, se ejecuta un rollback(lo que implica que si se llegase a introducir o ejecutar algún cambio no confirmado con nuestra conexión, todos y cada uno de ellos deben deshacerse, dejando la base de datos en un estado integro), se cierra la conexión y se retorna el error.

Si no ha ocurrido un error, se enviará la cantidad de filas afectadas por la sentencia, esto es vital para saber que no estamos alterando más allá de lo indispensable, ya hemos visto que un update mal confeccionado puede destruir toda la base de datos.

Entendiendo la inserción, quedan los ejemplos de todas las demás consultas de forma idéntica, simplemente cambiaremos la sentencia SQL por cada una de las operaciones que realizamos, un caso necesario para la mayoría de usuarios que ha sido imposible de realizar son las búsquedas amplias por nombre y apellidos, la palabra reservada like nos permite buscar cosas que no sean estrictamente igual a lo que busca el usuario, omitiendo mayúsculas y minúsculas(no son case sensitive), si bien es cierto es posible usar like, otros caracteres especiales como el % tienen un significado diferente entre SQL y Python, el modulo no nos provee una forma simple de resolver estas incompatibilidades, no nos permite hacer una verdadera consulta preparada y los profesionales en seguridad que he consultado me han confirmado que incluso evitar la inyección SQL es difícil, la solución mas fácil es colocar una coma al final de poner los datos, pero no es como tal una consulta preparada, cosa que si pueden encontrar en todos los módulos para conexión con bases de datos de otros lenguajes de programación.

Nuestro modulo de vista es a la vez la clase principal, main aquí empezamos a construir la GUI de forma mas creativa, tan creativa que acabo de encontrar un bug conocido de Qt5 de 2018 y empiezo a pensar que fue una mala idea intentar este proyecto mientras estudio dos módulos a la vez.

Sin muchas novedades la raíz de nuestra GUI será un objeto QMainWindow y las ventanas ahora si bien realizadas, son instancias de QFrame, de momento no he colocado nada más que un menú principal y la ventana de administración de personas, en esta ultima si que conseguí hacer una disposición interesante, los layout que tenemos son QVBoxLayout(Qt Vertical Box Layout) que ordena los componentes verticalmente y QHBoxLayout(Qt Horizontal Box Layout) que los ordena horizontalmente, a un modulo horizontal le agrego dos verticales y luego meto ese en otro vertical, consiguiendo dos espacios superiores(izquierdo y derecho) y un cajón inferior muy grande donde he puesto un area de texto QPlainTextEdit donde imprimo los errores, por que nada debería llegar a la consola teniendo una aplicación gráfica y bien reza el zen de python "Los errores nunca deben pasar silenciosamente".

Ese bonito componente de la fecha de nacimiento es a su vez un campo de texto con formato a gusto del consumidor y un calendario, en esta versión todo funciona perfectamente y no pretendo tocar nada a menos que sea estrictamente necesario o consiga comprender mucho mejor tanto QT5 como PyMySql, hasta aquí esta entrada, espero que les sea de utilidad, me tomó exactamente 7 días encontrar los problemas de pymysql y poner a funcionar a punto todo, así que no descarto tomarme unas vacaciones de python.

Comentarios

Entradas populares de este blog

Hablemos de difamación, parafilias y denuncias bien hechas

Criticamos a pablito: "Atrapado en el cuerpo equivocado"

El fruto de una era: Antiintelectualismo moderno