Carlos Andrés Restrepo Restrepo
Buenos días Luis, espero que se encuentre muy bien
Hice el curso de FastAPI y ahora estoy en este de Flask, excelentes cursos. Muchas gracias y así quedaron mis formularios.
La implementación de interfaces atractivas y funcionales es un aspecto fundamental en el desarrollo web moderno. Mientras que el backend proporciona la lógica y funcionalidad, el frontend es la cara visible de nuestra aplicación y determina en gran medida la experiencia del usuario. En este contenido, exploraremos cómo mejorar la apariencia de nuestra aplicación Flask utilizando Jinja, un poderoso sistema de plantillas que nos permite organizar y reutilizar nuestro código HTML de manera eficiente.
¿Qué es Jinja y cómo mejora nuestro desarrollo frontend?
Jinja es el manejador de plantillas integrado en Flask que ofrece grandes ventajas para el desarrollo frontend. Su principal beneficio es evitar la duplicación de código HTML, permitiéndonos mantener nuestro código organizado en diferentes archivos y reutilizarlo según sea necesario.
Para trabajar con Jinja de manera más eficiente, podemos instalar la extensión "Better Jinja" en nuestro editor de código, lo que facilita la escritura y el autocompletado de código Jinja.
Creando una plantilla base con Jinja
El primer paso para implementar Jinja en nuestra aplicación es crear una plantilla base que contendrá la estructura común a todas nuestras páginas:
base.html en la carpeta templates<!-- Seleccionamos Jinja HTML como lenguaje --> {% block app_notas %}{% endblock %} <body style="background-color: aqua;"> {% block content %}{% endblock %} </body>
Los bloques ({% block nombre %}{% endblock %}) son áreas que pueden ser sobrescritas por las plantillas que extiendan de esta base.
Extendiendo la plantilla base
Para utilizar nuestra plantilla base en otras vistas, usamos la directiva {% extends %}:
{% extends "base.html" %} {% block content %} <div> Lorem ipsum dolor sit amet... </div> {% endblock %}
Es importante entender que solo el contenido dentro de los bloques definidos será visible en la página final. Todo el contenido que no esté dentro de un bloque redefinido será ignorado.
¿Cómo implementar elementos comunes en todas las páginas?
Una de las ventajas de usar plantillas base es la capacidad de definir elementos que aparecerán en todas las páginas de nuestra aplicación, como barras de navegación, pies de página o sistemas de mensajes.
Sistema de mensajes flash
Para implementar un sistema de mensajes que aparezca en todas las páginas, podemos colocar el código correspondiente en la plantilla base:
<!-- En base.html, antes del bloque content --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} <div class="alert alert-{{ category }}">{{ message }}</div> {% endfor %} {% endif %} {% endwith %} {% block content %}{% endblock %}
De esta manera, los mensajes flash se mostrarán en cualquier página que extienda de nuestra plantilla base.
Mejorando la apariencia con Tailwind CSS
Para mejorar la apariencia de nuestra aplicación, podemos utilizar frameworks CSS como Tailwind. En nuestra plantilla base mejorada, incluimos:
<!-- Ejemplo de base.html mejorado --> <!DOCTYPE html> <html> <head> <title>{% block app_notas %}Notas App{% endblock %}</title> <script src="https://cdn.tailwindcss.com"></script> <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> </head> <body class="font-roboto"> <nav class="bg-blue-600 text-white p-4"> <h1 class="text-xl font-bold">Notas App</h1> </nav> <!-- Sistema de mensajes con colores según categoría --> {% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %} {% if category == 'success' %} <div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-4">{{ message }}</div> {% elif category == 'error' %} <div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4">{{ message }}</div> {% elif category == 'warning' %} <div class="bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 mb-4">{{ message }}</div> {% endif %} {% endfor %} {% endif %} {% endwith %} <main class="container mx-auto p-4"> {% block content %}{% endblock %} </main> <footer class="bg-gray-200 p-4 text-center text-gray-600"> © 2023 Notas App </footer> </body> </html>
¿Cómo personalizar las vistas específicas de nuestra aplicación?
Una vez que tenemos nuestra plantilla base, podemos personalizar cada vista específica extendiendo de ella y redefiniendo los bloques necesarios.
Personalizando la vista de inicio
Para la página principal que muestra la lista de notas, extendemos de la plantilla base y personalizamos el contenido:
{% extends "base.html" %} {% block app_notas %}Listado de Notas{% endblock %} {% block content %} <div class="flex justify-between items-center mb-4"> <h2 class="text-2xl font-bold">Mis Notas</h2> <a href="{{ url_for('create') }}" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Crear Nota </a> </div> {% if notes %} <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> {% for note in notes %} <div class="bg-white shadow-md rounded-lg p-4"> <h3 class="text-xl font-bold mb-2">{{ note.title }}</h3> <p class="text-gray-700 mb-4">{{ note.content }}</p> <p class="text-sm text-gray-500">Creada: {{ note.created_at }}</p> <div class="flex justify-end mt-4"> <a href="{{ url_for('edit', id=note.id) }}" class="bg-yellow-500 hover:bg-yellow-700 text-white font-bold py-1 px-3 rounded mr-2"> Editar </a> <a href="{{ url_for('delete', id=note.id) }}" class="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-3 rounded"> Eliminar </a> </div> </div> {% endfor %} </div> {% else %} <div class="bg-gray-100 p-8 text-center rounded-lg"> <p class="text-xl text-gray-600">No hay notas disponibles. ¡Crea una nueva!</p> </div> {% endif %} {% endblock %}
Agregando campos a nuestro modelo
Para mejorar nuestra aplicación, podemos agregar un campo de fecha de creación a nuestro modelo de Nota:
class Note(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) content = db.Column(db.Text, nullable=False) created_at = db.Column(db.DateTime, default=db.func.now())
El parámetro default=db.func.now() asegura que cada nueva nota tenga automáticamente la fecha y hora actual como su fecha de creación.
La implementación de Jinja en nuestra aplicación Flask nos permite crear interfaces más atractivas y mantener nuestro código organizado y reutilizable. Mediante el uso de plantillas base y bloques, podemos definir elementos comunes y personalizarlos según sea necesario en cada vista específica. Además, la integración con frameworks como Tailwind CSS nos facilita el diseño de interfaces modernas y responsivas. ¿Has implementado Jinja en tus proyectos Flask? Comparte tus experiencias y cómo has mejorado tus formularios con Tailwind en los comentarios.
Procedimiento para usar Flask Migrate:
1. Ejecuta:
pip install Flask-Migrate
2. En app.py añadir:
from flask_migrate import Migrate
migrate = Migrate(app, db) # <--- Añade esta línea
3. Ejecuta:
flask db init (Inicializa una vez por proyecto)
4. Agrega el campos al modelo
created_at = db.Column(db.DateTime, default=db.func.now(), nullable=True) # tiene que aceptar nulo pq existen registros
5. Ejecuta el comando:
flask db migrate -m "Add created_at column to Note"
6. Ejecuta:
flask db upgrade
Carlos Andrés Restrepo Restrepo
Buenos días Luis, espero que se encuentre muy bien
Hice el curso de FastAPI y ahora estoy en este de Flask, excelentes cursos. Muchas gracias y así quedaron mis formularios.
Carlos Enrique Angel Hernandez
Pueden solucionar con este codigo, desde la terminal >> flask shell luego resetar la BD >> db.drop_all(), luego db.create_all() por ultimo exit().. funciona pero no es recomendable para el ambiente de producción ya que estam,os reiniciando la DB
Jose Figueroa
Al escribir created_at = db.Column(db.DateTime, default=db.func.now()) en models.py , veo que no se agrega el campo en la base datos .
sqlite> .schema
CREATE TABLE note (
id INTEGER NOT NULL,
title VARCHAR(100) NOT NULL,
content VARCHAR(200) NOT NULL,
PRIMARY KEY (id)
);
Daniel Alberto Vera Angulo
Ya probaste volviendo a crear la tabla. era algo como db.create_all() algo asi recuerdo, lo ejecuta en el flask shell
Jeronimo Murillo Narvaez
Tal como decía Daniel, yo también estuve batallando con el mismo error… la base de datos no se actualizaba con la nueva columna y me salía el clásico error:
"no such column..."
Después de investigar un poco, encontré este artículo que me ayudó bastante: 🔗
Sé que existe una herramienta de migración (como Flask-Migrate), pero por cuestiones del ejercicio y para no complicarme, opté por una solución más sencilla:
backup.sqlite (por si necesitaba volver).notes.sqlite.Y listo, ¡problema solucionado!
Espero que a alguien más le sirva esta alternativa rápida ✌️
ANDRES ALFONSO MIRA MEJIA
✅