Aplicaciones web con Python

Aplicación web con Flask

2005 - Instituto Tecnológico de Mexicali

https://tinyurl.com/pyitm2025

Aplicaciones web con Python

Proyecto: Alcancía

  • Alcancía es una aplicacion web que
    • Registra depósitos
    • Registra retiros
    • Despliega un balance del dinero que contiene
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Solucion: Aplicación web con Flask

Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Herramientas de desarrollo

  • VSCode con el plugin de Python
    • ctrl+shift+P
    • Extensions: Install extensions
    • ms-python.python
  • UV, el administrador de proyectos en python (ver siguiente diapositiva)
  • Descargar DB Browser for SQLite desde https://sqlitebrowser.org/
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Instalación de uv

https://docs.astral.sh/uv/#getting-started

MacOS/Linux

curl -LsSf https://astral.sh/uv/install.sh | sh

Windows

Set-ExecutionPolicy RemoteSigned -scope CurrentUser
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Creación del proyecto

  • En una ventana de PowerShell creamos el proyecto inicial con uv
    uv init alcancia
    cd alcancia
    uv run .\hello.py
    
  • Abrir la carpeta alcancia en vscode:

    Archivo > Abrir carpeta.

  • Abrir una terminal en vscode
  • Ya podemos cerrar la ventana de PowerShell.
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Instalación de Flask

En la terminal de vscode:

uv add Flask
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Hola Mundo en flask

  • Creamos app.py con el siguiente contenido
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route("/")
    def hello_world():
        return "<p>Bienvenido a mi alcancia!</p>"
    
  • Levantamos el servidor de Flask
    uv run flask run --debug
    
  • Abrir http://127.0.0.1:5000
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Rutas

  • / > Raiz de la aplicacion. Muestra el balance
  • /deposito > Hacer un deposito
  • /retiro > Hacer un retiro
  • /movimientos > Histórico de movimientos
from flask import Flask

app = Flask(__name__)

@app.route("/")
def saldo():
    return "<p>Bienvenido a mi alcancia!</p><p>Tenemos <b>$0.00</b> pesos</p>"


@app.route("/deposito")
def deposito():
    return "<p>Aqui podras hacer un deposito</p>"


@app.route("/retiro")
def retiro():
    return "<p>Aqui podras hacer un retiro</p>"


@app.route("/movimientos")
def movimientos():
    return "<p>Lista de movimientos</p>"

Reiniciamos flask y probamos las rutas en el navegador.

Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Plantillas

  • Flask usa Jinja2
    • Herencia de plantillas, macros, autoescape, cacheo, etc.
  • Las plantillas se buscan en templates (relativo a app.py)

Layout de plantillas:

  • base.html -> Estructura comun de las demas.
  • saldo.html
  • deposito.html
  • retiro.html
  • movimientos.html
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Plantilla base

alt text

Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Plantilla de saldo

  • Crear saldo.html
    • No olvidar mostrar el valor de la variable saldo.
  • Modificar la ruta de saldo para usar la plantilla
    from flask import render_template
    
    @app.route("/")
    def saldo():
        return render_template('saldo.html', saldo=0.0)
    
    
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Plantilla de deposito

  • Crear deposito.html
  • Modificar la ruta de saldo para usar la plantilla
    from flask import render_template
    
    @app.route("/")
    def deposito():
        return render_template('deposito.html')
    
    
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Plantilla de retiro

  • Crear retiro.html
  • Modificar la ruta de saldo para usar la plantilla
    from flask import render_template
    
    @app.route("/")
    def retiro():
        return render_template('retiro.html')
    
    
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Plantilla de movimientos

  • Crear movimientos.html
  • Modificar la ruta de saldo para usar la plantilla
    from flask import render_template
    
    @app.route("/")
    def movimientos():
        return render_template('movimientos.html')
    
    
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Mensajes flash

Muy últiles para dar retroalimentación al usuario.

  • Configuración en Python
    from flask import flash
    
    
    app = Flask(__name__)
    app.secret_key = b'SVVMH3-lx0x1_jQ9LfBLWjo%qP'
    
    
  • Configuración en base.html
          <div class="content">
            <div class="block">
              {% with messages = get_flashed_messages(with_categories=true) %}
                {% if messages %}
                  <div class="notificaciones">
                  {% for category, message in messages %}
                    <div class="notification {{ category }}">
                      <button class="delete"></button>
                      {{ message }}
                    </div>
                  {% endfor %}
                  </div>
                {% endif %}
              {% endwith %}
            </div>
            <div class="block">
              {% block contenido %}{% endblock %}
            </div>
          </div>
    
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Formularios

  • Especificar methods en app.route(): POST y GET.
  • Flask define un objeto global llamado request.
  • El tipo de petición esta disposible desde request.method
  • Los datos del formulario estan en request.form.
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Primer formulario: /deposito - plantilla

  • Mensajes flash
      <form method="POST">
        {% if error %}
        <article class="message is-danger">
            <div class="message-body">
                Cantidad invalida
            </div>
        </article>
        {% endif %}
        <div class="field has-addons">
          ...
        </div>
      </form>
    
  • Formularios
      <form method="POST">
        {% if error %}
        ...
        {% endif %}
        <div class="field has-addons">
            <div class="control">
                <input class="input is-large" 
                type="number"
                min="0" 
                step="0.01" 
                placeholder="$ 0.00" 
                name="cantidad">
            </div>
            <div class="control">
                <input type="submit" value="&#x1FA99; Depositar"
                class="button is-info is-large">
            </div>
        </div>
      </form>
    
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Primer formulario: /deposito - Python

@app.route("/deposito")
def deposito():
    return render_template('deposito.html')
from flask import request, flash

@app.route("/deposito", methods=['POST', 'GET'])
def deposito():
    error = ''
    if request.method == 'POST':
        cantidad = request.form.get('cantidad', 0, type=int)
        if not cantidad:
            error = "Cantidad invalida"
        else:
            flash(f'Depositaste ${cantidad}')
    return render_template('deposito.html', error=error)

Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Actividad

Hacer el formulario de retiro

Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Listado de movimientos: plantilla

{% block contenido %}
  <table class="table is-bordered is-hoverable is-fullwidth">
    <thead>
      <tr>
        <td class="is-primary">Fecha</td>
        <td class="is-info">Cantidad</td>
      </tr>
    </thead>
    <tbody>
      {% for m in movimientos %}
      <tr>
        <td>{{ m.fecha }}</td>
        <td>{{ "${:,.2f}".format(m.cantidad) }}</td>
      </tr>
      {% endfor %}
    </tbody>
  </table>
{% endblock %}
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Listado de movimientos - Python

from flask import render_template

@app.route("/")
def movimientos():
    return render_template('movimientos.html')

  from datetime import datetime

  @app.route("/movimientos")
  def movimientos():
      return render_template('movimientos.html', movimientos=[
          {'fecha': datetime(year=2025, month=1, day=1), 'cantidad': 10},
          {'fecha': datetime(year=2025, month=1, day=2), 'cantidad': 10},
          {'fecha': datetime(year=2025, month=1, day=3), 'cantidad': 10},
          {'fecha': datetime(year=2025, month=1, day=4), 'cantidad': 10},
          {'fecha': datetime(year=2025, month=1, day=5), 'cantidad': -30},
      ])
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Lo que tenemos hasta ahora

  • Aplicación básica con 4 rutas
    1. Plantilla base configurada
    2. Reporte de saldo
    3. Dos formularios: depósitos y retiros
    4. Reporte de movimientos

Siguiente paso

  • Persistencia de datos
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Click

Click is a Python package for creating beautiful command line interfaces in a composable way with as little code as necessary. It’s the “Command Line Interface Creation Kit”. It’s highly configurable but comes with sensible defaults out of the box.

Flask usa click internamente para implementar su línea de comandos. Y nosotros podemos agregar subcomandos al comando flask

Instituto Tecnológico de Mexicali
Aplicaciones web con Python

SQLAlchemy

sql alchemy

  • ORM para Python
  • Dialectos soportados: SQLite, Postgresql, MySQL/MariaDB, Oracle, MS SQLServer. +30 dialectos soportados mediante librerías externas.
  • Flask-SQLAlchemy: integración de Flask con modelos de SQLAlchemy

Instalación

uv add Flask-SQLAlchemy
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Configurar ORM

  • Importar SQLAlchemy y click
  • Definir URI de la base de datos
  • Escribir clase para Movimiento
  • Escribir script para inicializar la bd
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.sql import func
import click

app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///alcancia.db"
db = SQLAlchemy(app)


class Movimiento(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    fecha = db.Column(db.DateTime, server_default=func.now())
    cantidad = db.Column(db.Numeric)


@app.cli.command()
def initdb():
    """
    Inicializa la base de datos de la alcancia
    """
    click.echo('Inicializando la base de datos')
    db.create_all()
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

El comando initdb

  • Primero verificar que el comando ya esta disponible
uv run flask
[...]
Commands:
  initdb  Inicializa la base de datos de la alcancia
  routes  Show the routes for the app.
  run     Run a development server.
  shell   Run a shell in the app context.
  • Crea la base de datos en instance/alcancia.db
  • Abrir la base de datos en DB Browser (SQLite) y confirmar que se ha creado la estructura de la BD.
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Persistir datos en la BD: depósitos

depo = Movimiento(cantidad=cantidad)
db.session.add(depo)
db.session.commit()
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Actividad

Implementar la ruta de retiros

Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Reporte de saldo

  • En app.py
    from sqlalchemy.sql import func
    
    @app.route("/")
    def saldo():
        return render_template(
            'saldo.html',
            saldo=db.session.scalar(func.sum(Movimiento.cantidad))
        )
    
  • En templates/saldo.html
{% block contenido %}
  <h2>El saldo es <b> {{"$%.2f"|format(saldo)}} </b></h2>
{% endblock %}
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Reporte de movimientos

En app.py

@app.route("/movimientos")
def movimientos():
    q = db.session.execute(db.select(Movimiento).order_by(Movimiento.fecha))
    return render_template('movimientos.html', movimientos=q.scalars())
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Reporte de movimientos

En templates/saldo.html

{% block contenido %}
  <table class="table is-bordered is-hoverable is-fullwidth">
    <thead>
      <tr>
        <td class="is-primary">Fecha</td>
        <td class="is-info">Cantidad</td>
      </tr>
    </thead>
    <tbody>
      {% for m in movimientos %}
      <tr>
        <td>{{ m.fecha }}</td>
        <td>{{ "${:,.2f}".format(m.cantidad) }}</td>
      </tr>
      {% endfor %}
    </tbody>
  </table>
{% endblock %}
Instituto Tecnológico de Mexicali
Aplicaciones web con Python

Siguiente: Agregando un API Rest →

Instituto Tecnológico de Mexicali