¿Cómo crear aplicaciones con Python – MySQL y Tkinter? – Parte 1 – Máster en Python #26

Seguimos con el manejo de bases de datos desde Python con MySQL. En esta ocasión vamos a empezar un proyecto muy ambicioso con interfaces gráficas de Python y MySQL.

Vamos a crear un programa de interfaz gráfica con Tkinter, con la que conectar a un servidor cualquiera MySQL y trabajaremos con él.

Para ello, haremos una biblioteca con muchas funciones para trabajar directamente con en el servidor.

Haremos las siguientes cosas en los próximos capítulos:

  • Crear una biblioteca con funciones para trabajar con MySQL desde Python.
  • Crearemos después una interfaz gráfica que maneje muchas de esas funciones (no todas, porque se alargará demasiado el proyecto).

Entonces, en el programa tendremos todo esto:

El programa podrá realizar todas estas tareas:

  • Conectar con un servidor MySQL cualquiera.
  • Entrada con login.
  • Hacer consultas SQL de todo tipo y presentarlas.
  • Mostrar bases de datos de servidores MySQL.
  • Crear bases de datos MySQL.
  • Eliminar bases de datos MySQL.
  • Crear copias de seguridad.
  • Manejar fechas y horas y asignarlas a los nombres de las copias.
  • Crear tablas.
  • Eliminar tablas.
  • Mostrar tablas de una base de datos.
  • Mostrar columnas de tablas.
  • Insertar registros en tablas.
  • Consultar registros.
  • Eliminar registros.
  • Actualizar registros.

Para realizar esta ambiciosa tarea, vamos a utilizar todo lo aprendido hasta ahora desde el principio del curso y más cosas. El proyecto utilizará lo siguiente:

  • Variables.
  • Salida y entrada de datos al programa.
  • Conversiones de tipos de datos.
  • Condicionales.
  • Listas, tuplas y diccionarios.
  • Bucles.
  • Funciones y métodos.
  • Interfaces gráficas con Tkinter.
  • Funciones lambda.
  • Programación orientada a objetos avanzada.
  • Eventos.
  • Manejo avanzado de strings.
  • Programación modular.
  • MySQL connector para Python.
  • *args y **kwargs.
  • Funciones decoradoras orientadas a clases.
  • Manejo de horas y fechas.
  • String slicing.
  • Y alguna sorpresa más.

A medida que vayamos tocando un tema que ya hayamos dado, te indicaré en qué capítulo ya expliqué el tema, así, si necesitas refrescar la memoria, podrás hacerlo rápidamente sin perderte en el extenso temario del curso.

Si tienes dudas, abajo de cada capítulo tienes la caja de comentarios.

¿Empezamos ya?

Preparar el proyecto Python – MySQL – Tkinter

Lo primero que tendrá nuestra aplicación, será la conexión con la base de datos. Este programa, lo vamos a realizar con programación modular. Tema que traté en el capítulo 17. De modo, que cada parte del programa, estará hecha en un módulo.

Crea un nuevo proyecto Python (haz una carpeta y ábrela con el programa que utilices). Este es el que he creado yo:

inicio del proyecto Python

Lo siguiente, será hacer un archivo nuevo en la raíz del proyecto. Este será el que trabajará con todos los módulos que creemos:

archivo principal del proyecto python

Ahora, crea una carpeta en la raíz y añade un archivo para escribir la conexión con la base de datos y otro __init__.py:

archivo paquete Python __init__.py

¿Para qué sirve el archivo __init__.py?

El archivo __init__.py casi siempre está vacío. Lo tenemos que crear para que el intérprete de Python maneje la carpeta como un paquete de Python y no como una simple carpeta.

¿Qué son los paquetes de Python?

Sencillamente, son agrupaciones de varios módulos en una carpeta, con un archivo __init__.py.

Creando la conexión MySQL – Python con la base de datos

Ahora, en el archivo base_datos.py, vamos a hacer todo lo necesario para conectar con la base de datos.

Si no has seguido el curso hasta aquí, te recomiendo que veas los tres capítulos anteriores para tener contexto de todo lo que voy haciendo.

El primer paso es importar «mysql.connector»:

import mysql.connector

Después, debemos crear un diccionario con los datos de conexión al servidor MySQL. Esto lo puedes hacer en este mismo archivo o bien creamos otro. De momento, para no liarte, lo voy a poner todo junto en base_datos.py.

Los diccionarios, los tienes en el capítulo 7, por si no los recuerdas muy bien. También se han dado en el capítulo 22 con el uso de *args y **kwargs.

#conexión con la base de datos
acceso_bd = {"host" : "localhost",
            "user" : "root",
            "password" : "programacionfacil",
            "database" : "american_rider"
            }

Clase de conexión MySQL desde Python

Ahora, vamos a crear nuestra propia clase para trabajar con el servidor. A esta clase, le podemos ir añadiendo métodos para ir haciendo acciones, por ejemplo, un método para mostrar las bases de datos que hay en el servidor.

Las clases las dimos en el capítulo 11 del curso. Aquí voy a añadirle más cosas que no habíamos dado. También en el capítulo 23.

Por si no tienes muy fresco el manejo del lenguaje SQL junto con Python, te recomiendo que veas los capítulos 19, 20 y 21.

Método __init__

El método __init__, llevará un único parámetro, **kwargs.

El método que estoy utilizando en la línea 3, es el mysql.connect que hemos utilizado hasta ahora, pasando los datos de conexión del servidor MySQL.

La idea de esto, es que cuando crees un objeto de tipo «BaseDatos», le pases el nombre de un diccionario con los datos de conexión.

class BaseDatos:
    def __init__(self, **kwargs):
        self.conector = mysql.connector.connect(**kwargs)

Método consulta

Lo primero, es tener una conexión con el servidor, lo segundo, manejar el cursor para poder realizar acciones en ella.

Bien, creemos un método que estará preparado para hacer consultas SQL en nuestras bases de datos.

En este método, creo el cursor de la misma forma que expliqué anteriormente. Esta vez, en lugar de llamar a la variable cursor y después mandarle un execute(), le haré directamente una llamada con la consulta SQL, de esa forma, dejamos aparentemente, el lenguaje SQL de forma nativa en nuestro programa.

    def consulta(self, sql):
        self.cursor = self.conector.cursor()
        self.cursor.execute(sql)
        return self.cursor

La llamada a este método, podrá ser algo como este ejemplo:

consulta("SHOW DATABASES")

Los objetos que creemos a partir de la clase BaseDatos, tendrán la «inteligencia» suficiente como para conectarse a servidores MySQL y ejecutar consultas con esa simple llamada.

El contenido final del archivo base_datos.py, debería quedarte como este:

import mysql.connector

#conexión con la base de datos
acceso_bd = {"host" : "localhost",
            "user" : "root",
            "password" : "programacionfacil",
            "database" : "american_rider"
            }

#clase para trabajar con bases de datos
class BaseDatos:
    def __init__(self, **kwargs):
        self.conector= mysql.connector.connect(**kwargs)
        
    def consulta(self, sql):
        self.cursor = self.conector.cursor()
        self.cursor.execute(sql)
        return self.cursor

Archivo app.py

Importación

Volvamos al archivo app.py, el archivo principal (el de la raíz).

Aquí, realicemos la importación del archivo base_datos.py

#importaciones
import bd.conexion as sqlbd

Instancia

Una vez importado el módulo, ya podemos instanciar un objeto de la clase BaseDatos.

Que no te abrume esta línea. Analicémosla para que se entienda mejor.

base_datos = sqlbd.BaseDatos(**sqlbd.acceso_bd)

Se instancia de BaseDatos el objeto «base_datos». Como único parámetro que espera el __init__, le paso el diccionario de conexión correspondiente para **kwargs.

Esta vez, el diccionario está en el mismo módulo «base_datos.py», por ese motivo, accedo a dicho diccionario mediante «sqlbd», que es el alias del módulo y acceso_bd, el nombre del diccionario.

Si te costase mucho seguir el hilo de estas explicaciones, te recomiendo que veas el vídeo de arriba, seguramente lo entenderás mejor.

Consulta al servidor MySQL

Ahora que ya tenemos este magnífico objeto, lo podemos utilizar despreocupándonos de la conexión con el servidor o el manejo del cursor. Lo hace solo.

Para realizar una consulta, solo tendrás que llamar al método consulta() que tiene el objeto y pasarle una instrucción SQL.

Veamos, por ejemplo, las bases de datos que hay en el servidor.

#importaciones
import bd.conexion as sqlbd

#objeto
base_datos = sqlbd.BaseDatos(**sqlbd.acceso_bd)

#consultar bases de datos en el servidor
consulta_1 = base_datos.consulta("SHOW DATABASES")

for bd in consulta_1: # type: ignore
    print(bd)

Resultado en la consola

(‘american_rider’,)
(‘information_schema’,)
(‘mysql’,)
(‘performance_schema’,)
(‘pruebas’,)
(‘sakila’,)
(‘sys’,)
(‘world’,)

Por lo del bucle, lo expliqué hace dos o tres capítulos.

Mejoras para la clase

Esta clase puede llegar a ser una clase con verdaderos superpoderes. La podemos dotar de una enorme cantidad de cosas. Tu imaginación y experiencia, determinarán el límite.

Por ejemplo, ¿no te gusta tener que poner un bucle en conjunto a la llamada consulta() para que funcione?

Mejora la clase y añade un método que haga todo el trabajo sucio.

Ahí lo tienes. Al llamar a este nuevo método, dispondremos automáticamente de la conexión, gracias a la clase, ejecutaremos con el cursor el comando específico para mostrar bases de datos y el bucle con un print y todo (que puede ser un return si no quieres imprimir, quizás lo quieras para devolver al programa).

    def mostrar_bd(self):
        self.cursor.execute("SHOW DATABASES")
        for bd in self.cursor: # type: ignore
            print(bd)

La llamada es esta:

base_datos.mostrar_bd()

Sin embargo, esto nos arroja un error:

Error en la consola

AttributeError: ‘BaseDatos’ object has no attribute ‘cursor’

El error está en un atributo faltante. Esto es, porque el atributo cursor está en el método consulta(). Debido al alcance del atributo, no podemos utilizar un método de una a otra función.

Una solución, sería declarar un nuevo atributo con el cursor dentro del método nuevo también. ¿Crees que es una buena solución? La respuesta es que no, ya que si tenemos 50 métodos que usan el cursor, tendremos 50 cursores.

Te dejo como reto, que intentes solucionar el problema. Que consigas crear un solo cursor que sirva para los dos métodos y los que vengan en los próximos capítulos.

Si no sabes como, no te preocupes. En el siguiente capítulo lo solucionaré.

Solución al ejercicio del capítulo anterior

Aquí está una posible solución al ejercicio del capítulo anterior:

def decorador(funcion_parametro):
    def interna(**kwargs):
        print("Leyendo el diccionario...")
        funcion_parametro(**kwargs)
        print("Operación realizada con éxito.")
    return interna

@decorador
def muestra_datos(**kwargs):
    claves = tuple(kwargs.keys())
    valores = tuple(kwargs.values())
    print(f"El {claves[0]} es {valores[0]}, sus {claves[1]} son {valores[1]} y tiene {valores[2]} años de {claves[2]}.")

usuario1 = {"nombre":"Javier", "apellidos":"Gómez de la barca", "edad":"27"}

muestra_datos(**usuario1)

El resultado en la consola es este:

Resultado en la consola

Leyendo el diccionario…
El nombre es Javier, sus apellidos son Gómez de la barca y tiene 27 años de edad.
Operación realizada con éxito.

No te pierdas nada de todo el contenido que tengo sobre Python.

5 respuestas a «¿Cómo crear aplicaciones con Python – MySQL y Tkinter?»

  1. Hay leve confusion en las importaciones «import bd.conexion» usas «conexion» me imagino claro creaste un modulo aparte, pero nos guias con el de «base_datos» Y en ese punto usas otra cosa, para verificar mire tu video y ahi si lo colocas como explicas en todo el temario. Saludos, de resto excelente todo!

  2. Cómo crear un programa con base de datos en sqlite3 y tkinter. Porque no me deja instalar MySQL

  3. Avatar de Oscar Hernández
    Oscar Hernández

    No consigo descargar MySQL, no hay manera

    1. Hola, ¿qué problema tienes exactamente? ¿Te sale algún error cuando intentas descargar e instalar con pip? ¿Lo instalas y no te hace el import?

  4. […] con el proyecto que empecé en el capítulo 26. Un proyecto para aprender a crear aplicaciones que utilicen Python, MySQL y […]

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Trending