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
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
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
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
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:
pip install pymysql
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.
me interesaría ver como manejar data-table con python y flask
y como lo subo a un hosting? si no puedo instalar eso
Sería cuestión de contratar un VPS o un hosting donde se permitan instalar estas apps
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
Hola. Gracias por sus comentarios. Si tiene alguna consulta con gusto lo atiendo en https://parzibyte.me/#contacto
Saludos!
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.