python

Flask con MySQL – Ejemplo de conexión (CRUD)

En el artículo de hoy te enseñaré cómo crear una aplicación web usando Flask, Python y MySQL. Vamos a ver cómo hacer una conexión a la base de datos de MySQL desde Flask y realizar todas las operaciones de insertar, actualizar, mostrar y eliminar.

Al final tendremos una web que será un CRUD, trabajando con formularios, plantillas, rutas, etcétera.

Conectando Python con MySQL

Preparando base de datos MySQL para conectar con Flask

Como lo dije anteriormente, vamos a conectar a MySQL / MariaDB así que vamos a usar PyMySQL para este enlace. Encerramos el comportamiento en una función y se ve así:

import pymysql


def obtener_conexion():
    return pymysql.connect(host='localhost',
                                user='root',
                                password='',
                                db='juegos')

Recuerda cambiar las credenciales de acuerdo a tu entorno. Por cierto, nuestra aplicación de ejemplo va a gestionar videojuegos. No olvides crear la base de datos con anterioridad, e instalar obviamente MySQL.

Por cierto, la creación de la tabla queda como se ve a continuación:

CREATE TABLE juegos(
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
    nombre VARCHAR(255) NOT NULL,
    descripcion VARCHAR(255) NOT NULL,
    precio DECIMAL(9,2) NOT NULL
);

Controlador

Hasta este punto tenemos la conexión con la base de datos, pero vamos a exponer todos los métodos usando un controlador, que no es más que un archivo que expone ciertas funciones con respecto a la gestión de juegos.

En este archivo es en donde creamos los métodos para las consultas SQL para más tarde exponerlos desde cualquier ruta en Flask. Por lo tanto el archivo queda así:

from bd import obtener_conexion


def insertar_juego(nombre, descripcion, precio):
    conexion = obtener_conexion()
    with conexion.cursor() as cursor:
        cursor.execute("INSERT INTO juegos(nombre, descripcion, precio) VALUES (%s, %s, %s)",
                       (nombre, descripcion, precio))
    conexion.commit()
    conexion.close()


def obtener_juegos():
    conexion = obtener_conexion()
    juegos = []
    with conexion.cursor() as cursor:
        cursor.execute("SELECT id, nombre, descripcion, precio FROM juegos")
        juegos = cursor.fetchall()
    conexion.close()
    return juegos


def eliminar_juego(id):
    conexion = obtener_conexion()
    with conexion.cursor() as cursor:
        cursor.execute("DELETE FROM juegos WHERE id = %s", (id,))
    conexion.commit()
    conexion.close()


def obtener_juego_por_id(id):
    conexion = obtener_conexion()
    juego = None
    with conexion.cursor() as cursor:
        cursor.execute(
            "SELECT id, nombre, descripcion, precio FROM juegos WHERE id = %s", (id,))
        juego = cursor.fetchone()
    conexion.close()
    return juego


def actualizar_juego(nombre, descripcion, precio, id):
    conexion = obtener_conexion()
    with conexion.cursor() as cursor:
        cursor.execute("UPDATE juegos SET nombre = %s, descripcion = %s, precio = %s WHERE id = %s",
                       (nombre, descripcion, precio, id))
    conexion.commit()
    conexion.close()

Básicamente tenemos varias funciones que reciben los argumentos necesarios para cada caso. El nombre de cada función indica lo que hace, pero todas ellas hacen una consulta SQL a la base de datos.

Si quieres ver un tutorial más enfocado a la conexión, puedes ver uno que hice hace tiempo, ya que aquí el objetivo es un CRUD de Flask con MySQL.

Flask y MySQL

Es momento de exponer las rutas y crear la app web con Flask. Vamos paso por paso explicando poco a poco.

Plantilla maestra

Voy a reutilizar las plantillas para evitar repetir código. Esto lo podemos hacer de manera muy simple usando Jinja. Si quieres ver esto en profundidad puedes leer mi otro post, aunque es muy sencillo.

Como sea, la plantilla base queda así:

<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!--Poner un block para que luego pueda ser remplazado en las siguientes plantillas; lo mismo con el  block contenido-->
    <title>CRUD MySQL con Flask - {% block titulo %}{% endblock %}</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css">
</head>

<body>
    <nav class="navbar is-warning" role="navigation" aria-label="main navigation">
        <div class="navbar-brand">
            <a href="https://parzibyte.me/blog" class="navbar-item">
                <img alt="Logo de Parzibyte"
                    src="https://raw.githubusercontent.com/parzibyte/ejemplo-mern/main/src/img/parzibyte_logo.png"
                    style="max-height: 80px" />
            </a>
            <button class="navbar-burger is-warning button" aria-label="menu" aria-expanded="false"
                data-target="navbarBasicExample">
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
                <span aria-hidden="true"></span>
            </button>
        </div>
        <div class="navbar-menu">
            <div class="navbar-start">
                <a class="navbar-item" href="{{url_for('juegos')}}">Juegos</a>
            </div>
            <div class="navbar-end">
                <div class="navbar-item">
                    <div class="buttons">
                        <a href="https://parzibyte.me#contacto" class="button is-primary">
                            <strong>Ayuda y soporte</strong>
                        </a>
                    </div>
                </div>
            </div>
        </div>
    </nav>
    {%block contenido %} {% endblock %}
</body>

</html>

De modo que ahora simplemente vamos a extender de ella en todas las otras templates.

Insertar juego con formulario

Formulario para insertar datos usando Flask y MySQL

Para insertar un juego primero debemos mostrar el formulario con Flask, renderizando la plantilla:

@app.route("/agregar_juego")
def formulario_agregar_juego():
    return render_template("agregar_juego.html")

La plantilla es cuestión es la siguiente:

{% extends "maestra.html" %}
{% block titulo %}
Agregar juego
{% endblock %}
{% block contenido %}
<section class="section">
    <div class="columns">
        <div class="column">
            <h3 class="is-size-3">Agregar juego</h3>
            <form action="{{url_for('guardar_juego')}}" method="post">
                <label for="nombre">Nombre:</label>
                <input required type="text" class="input" placeholder="Nombre" name="nombre" id="nombre">
                <label for="descripcion">Descripción</label>
                <input required type="text" class="input" placeholder="Descripción" name="descripcion" id="descripcion">
                <label for="precio">Precio</label>
                <input required type="number" class="input" placeholder="Precio" name="precio" id="precio">
                <button type="submit" class="button is-success mt-2">Guardar</button>
                <a href="{{url_for('juegos')}}" class="button is-primary mt-2">Volver</a>
            </form>
        </div>
    </div>
</section>
{% endblock %}

En la misma solo tenemos un formulario HTML que tiene los input nombre, descripcion y precio que más tarde vamos a procesar en la ruta /guardar_juego usando Flask.

Al enviar el formulario llegamos a la siguiente ruta:

@app.route("/guardar_juego", methods=["POST"])
def guardar_juego():
    nombre = request.form["nombre"]
    descripcion = request.form["descripcion"]
    precio = request.form["precio"]
    controlador_juegos.insertar_juego(nombre, descripcion, precio)
    # De cualquier modo, y si todo fue bien, redireccionar
    return redirect("/juegos")

Y justo ahí es en donde tomamos los valores del formulario, invocamos al método del controlador y hacemos una redirección hacia el listado de juegos.

Listado de juegos – Consulta SQL select

Listar juegos en tabla HTML usando Python, MySQL y Flask

Ahora vamos al siguiente apartado que es el listado de videojuegos. En este caso renderizamos la plantilla con Flask, pero además le pasamos los juegos que se van a mostrar en una tabla HTML.

@app.route("/")
@app.route("/juegos")
def juegos():
    juegos = controlador_juegos.obtener_juegos()
    return render_template("juegos.html", juegos=juegos)

Si te fijas le estamos pasando la variable (previamente obtenida del controlador) en la línea 5, como segundo argumento a render_template. Más tarde, en la plantilla, hacemos un ciclo for para iterar sobre todos los juegos y dibujar la tabla:

{% extends "maestra.html" %}
{% block titulo %} Juegos {% endblock %}
{% block contenido %}

<section class="section">
    <div class="columns">
        <div class="column">
            <h3 class="is-size-3">Juegos</h3>
            <a href="{{url_for('formulario_agregar_juego')}}" class="button is-success">Agregar</a>
            <table class="table">
                <thead>
                    <tr>
                        <th>Nombre</th>
                        <th>Descripción</th>
                        <th>Precio</th>
                        <th>Editar</th>
                        <th>Eliminar</th>
                    </tr>
                </thead>
                <tbody>
                    {% for juego in juegos %}
                    <tr>
                        <td>{{juego[1]}}</td>
                        <td>{{juego[2]}}</td>
                        <td>{{juego[3]}}</td>
                        <td>
                            {# Pasar el id (lo que hay en juego[0] #}
                            <a href="{{url_for('editar_juego', id=juego[0])}}" class="button is-info">Editar</a>
                        </td>
                        <td>
                            <form action="{{url_for('eliminar_juego')}}" method="POST">
                                <input type="hidden" name="id" value="{{juego[0]}}">
                                <button class="button is-danger">Eliminar</button>
                            </form>
                        </td>
                    </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>
    </div>
</section>
{% endblock %}

Y así es como se dibuja la tabla. Por cierto fíjate en que tenemos dos columnas especiales. Una de ellas es un enlace que lleva a la plantilla para editar, pasando el id. La otra es un formulario que lleva el id del juego en un input oculto, y que, como bien dice, es para eliminar el juego.

Eliminar juego – Operación delete en MySQL

Es momento de ver la operación para eliminar un registro de la base de datos de MariaDB / MySQL. Ya te mostré anteriormente el método del controlador, ahora veamos la ruta en donde lo exponemos:

@app.route("/eliminar_juego", methods=["POST"])
def eliminar_juego():
    controlador_juegos.eliminar_juego(request.form["id"])
    return redirect("/juegos")

Como puedes ver solo necesitamos que se nos envíe, dentro del formulario, el id. Y eso lo hacemos anteriormente al dibujar la tabla.

Operación update

Editar registro con MySQL y Flask

Para terminar el tutorial veamos cómo realizar una actualización de datos en este CRUD con Flask y MySQL. Primero te enseñaré la ruta que recibe el id del juego, obtiene el registro por id y muestra la plantilla con el formulario para editar:

@app.route("/formulario_editar_juego/<int:id>")
def editar_juego(id):
    # Obtener el juego por ID
    juego = controlador_juegos.obtener_juego_por_id(id)
    return render_template("editar_juego.html", juego=juego)

En este caso obtenemos el juego por ID y renderizamos la plantilla pasándole el dato, justo como cuando mostrábamos la lista completa de los juegos. Y ahora en el formulario rellenamos el campo indicando el atributo value de cada input:

{% extends "maestra.html" %}
{% block titulo %}
Editar juego
{% endblock %}
{% block contenido %}
<section class="section">
    <div class="columns">
        <div class="column">
            <h3 class="is-size-3">Editar juego</h3>
            <form action="{{url_for('actualizar_juego')}}" method="post">
                {# Enviar el id en un campo oculto #}
                <input type="hidden" name="id" value="{{juego[0]}}">
                <label for="nombre">Nombre:</label>
                <input value="{{juego[1]}}" required type="text" class="input" placeholder="Nombre" name="nombre" id="nombre">
                <label for="descripcion">Descripción</label>
                <input value="{{juego[2]}}" required type="text" class="input" placeholder="Descripción" name="descripcion" id="descripcion">
                <label for="precio">Precio</label>
                <input value="{{juego[3]}}" required type="number" class="input" placeholder="Precio" name="precio" id="precio">
                <button type="submit" class="button is-success mt-2">Guardar</button>
                <a href="{{url_for('juegos')}}" class="button is-primary mt-2">Volver</a>
            </form>
        </div>
    </div>
</section>
{% endblock %}

Fíjate en que dentro de la línea 12 estamos incluyendo el ID del juego que vamos a actualizar, de manera oculta. Ahora, cuando ese formulario se envíe se va a procesar en el siguiente fragmento de código de Python:

@app.route("/actualizar_juego", methods=["POST"])
def actualizar_juego():
    id = request.form["id"]
    nombre = request.form["nombre"]
    descripcion = request.form["descripcion"]
    precio = request.form["precio"]
    controlador_juegos.actualizar_juego(nombre, descripcion, precio, id)
    return redirect("/juegos")

De nuevo estamos recogiendo valores del formulario, invocando a nuestro controlador y redireccionando. Seguimos el mismo patrón de antes, reutilizando código y haciéndolo de manera sencilla.

Poniendo todo junto

Hasta este punto te he mostrado el código detallado de esta aplicación web que usa Python, Flask y MySQL. Adicional a ello te voy a dejar el código completo en mi GitHub para que puedas descargarlo y probarlo por ti mismo.

Recuerda que debes contar con MySQL, Python y pip instalados. También debes crear la base de datos y la tabla.

Luego instala las dependencias con:

  1. pip install pymysql
  2. pip install flask

Finalmente ejecuta:

python main.py

Y ahora puedes visitar la aplicación en http://localhost:8000/

Recuerda que en mi blog tengo todavía más tutoriales de programación con Python y Flask, además de otros posts sobre MySQL.

Por cierto, hablando de estas tecnologías, anteriormente te enseñé cómo hacer una API REST con Flask y SQLite3.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Ver comentarios

  • Estoy siguiendo sus videos y me gusta este crud, tengo una duda al desplegar un proyecto como este o similiar hecho en flask la base de datos en mysql sin un utilizar sqlalchemy, heroku o pythonanywhere lee el codigo de la base de datos como sql, o necesariamente debe estar creado como una clase para que el servidor lea la base de datos y la cree??
    Quedo atento a su comentario y gracias por estos tutoriales me ayudan mucho

  • ESÉCTACULAR IMPECABLE EL TUTORIAL!!!. MUCHISIMA GRACIAS MAESTRO.!!! ME AYUDASTE MUCHISIMO. GRACIAS!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  • Hola, antes de nada, darte las gracias por compartir tu trabajo.
    En segundo lugar ando buscando consejo, estoy realizando una aplicación web con PHP que gestiona datos importados de hojas Excel y los guarda en BBDD. Con estos datos la aplicación muestra diferentes tipos de gráficos en función de lo que el usuario seleccione.
    Por otra parte, tengo un código Python que analiza por medio de redes neuronales datos de las mismas hojas Excel.
    Me gustaría saber como podría integrar el código Python en la aplicación web, y tener una sección donde poder analizar con la redes neuronales los datos que administra la aplicación.
    Cualquier consejo me sería de gran ayuda.
    Un saludo, gracias.

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

1 semana hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

2 semanas hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

2 semanas hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

2 semanas hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

2 semanas hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

2 semanas hace

Esta web usa cookies.