Cómo usar Flask-SQLAlchemy para interactuar con bases de datos en una aplicación Flask

El autor seleccionó el Fondo de Software Libre y de Código Abierto para recibir una donación como parte del programa Escribir para Donaciones.

Introducción

En las aplicaciones web, generalmente necesitas una base de datos, que es una colección organizada de datos. Utilizas una base de datos para almacenar y mantener datos persistentes que se pueden recuperar y manipular de manera eficiente. Por ejemplo, en una aplicación de redes sociales, tienes una base de datos donde se almacenan los datos de los usuarios (información personal, publicaciones, comentarios, seguidores) de una manera que se puede manipular de manera eficiente. Puedes agregar datos a una base de datos, recuperarlos, modificarlos o eliminarlos, dependiendo de diferentes requisitos y condiciones. En una aplicación web, estos requisitos podrían ser que un usuario agregue una nueva publicación, elimine una publicación o elimine su cuenta, lo que puede o no eliminar sus publicaciones. Las acciones que realices para manipular datos dependerán de las características específicas de tu aplicación. Por ejemplo, es posible que no desees que los usuarios agreguen publicaciones sin títulos.

Implementa tus aplicaciones de Flask desde GitHub utilizando la Plataforma de Aplicaciones de DigitalOcean. Deja que DigitalOcean se centre en hacer crecer tu aplicación.

Flask es un marco web ligero de Python que proporciona herramientas útiles y características para crear aplicaciones web en el lenguaje Python. SQLAlchemy es un kit de herramientas SQL que proporciona acceso eficiente y de alto rendimiento a bases de datos relacionales. Proporciona formas de interactuar con varios motores de base de datos como SQLite, MySQL y PostgreSQL. Le brinda acceso a las funcionalidades SQL de la base de datos. También le brinda un Mapeador Relacional de Objetos (ORM), que le permite realizar consultas y manipular datos utilizando objetos y métodos simples de Python. Flask-SQLAlchemy es una extensión de Flask que facilita el uso de SQLAlchemy con Flask, proporcionándole herramientas y métodos para interactuar con su base de datos en sus aplicaciones Flask a través de SQLAlchemy.

En este tutorial, construirás un pequeño sistema de gestión de estudiantes que demuestra cómo usar la extensión Flask-SQLAlchemy. Lo usarás con Flask para realizar tareas básicas, como conectarte a un servidor de base de datos, crear una tabla, agregar datos a tu tabla, recuperarlos y actualizar y eliminar elementos de tu base de datos. Usarás SQLAlchemy con SQLite, aunque también puedes usarlo con otros motores de base de datos, como PostgreSQL y MySQL. SQLite funciona bien con Python porque la biblioteca estándar de Python proporciona el módulo sqlite3, que es utilizado por SQLAlchemy detrás de escena para interactuar con bases de datos SQLite sin tener que instalar nada. SQlite se instala en sistemas Linux de forma predeterminada, y se instala como parte del paquete Python en Windows.

Prerrequisitos

Paso 1 — Instalación de Flask y Flask-SQLAlchemy

En este paso, instalarás los paquetes necesarios para tu aplicación.

Con tu entorno virtual activado, utiliza pip para instalar Flask y Flask-SQLAlchemy:

  1. pip install Flask Flask-SQLAlchemy

Una vez que la instalación haya finalizado con éxito, verás una línea similar a la siguiente al final de la salida:

Output
Successfully installed Flask-2.0.3 Flask-SQLAlchemy-2.5.1 Jinja2-3.0.3 MarkupSafe-2.1.0 SQLAlchemy-1.4.31 Werkzeug-2.0.3 click-8.0.4 greenlet-1.1.2 itsdangerous-2.1.0

Con los paquetes de Python requeridos instalados, configurarás la base de datos a continuación.

Paso 2 — Configuración de la Base de Datos y el Modelo

En este paso, configurarás la conexión a tu base de datos y crearás un modelo de base de datos SQLAlchemy, que es una clase de Python que representa la tabla que almacena tus datos. Iniciarás la base de datos, crearás una tabla para los estudiantes basada en el modelo que declararás y agregarás algunos estudiantes a tu tabla de estudiantes.

Configuración de la Conexión a la Base de Datos

Abre un archivo llamado app.py en tu directorio flask_app. Este archivo contendrá código para configurar la base de datos y tus rutas de Flask:

  1. nano app.py

Este archivo se conectará a una base de datos SQLite llamada database.db, y tendrá una clase llamada Student que representa tu tabla de estudiantes de la base de datos para almacenar información de los estudiantes, además de tus rutas de Flask. Agrega las siguientes declaraciones de import en la parte superior de app.py:

flask_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy.sql import func

Aquí, importas el módulo os, que te da acceso a interfaces de sistema operativo varias. Lo utilizarás para construir una ruta de archivo para tu archivo de base de datos database.db.

Desde el paquete flask, luego importas los ayudantes necesarios para tu aplicación: la clase Flask para crear una instancia de la aplicación Flask, la función render_template() para renderizar plantillas, el objeto request para manejar las solicitudes, la función url_for() para construir URLs para rutas, y la función redirect() para redirigir usuarios. Para obtener más información sobre rutas y plantillas, consulta Cómo usar plantillas en una aplicación Flask.

Luego importas la clase SQLAlchemy de la extensión Flask-SQLAlchemy, que te proporciona acceso a todas las funciones y clases de SQLAlchemy, además de ayudantes y funcionalidades que integran Flask con SQLAlchemy. Lo usarás para crear un objeto de base de datos que se conecta a tu aplicación Flask, lo que te permite crear y manipular tablas usando clases, objetos y funciones de Python sin necesidad de usar el lenguaje SQL.

También importas el ayudante func del módulo sqlalchemy.sql para acceder a funciones SQL. Lo necesitarás en tu sistema de gestión de estudiantes para establecer una fecha y hora de creación predeterminada cuando se cree un registro de estudiante.

Después de las importaciones, configurarás la ruta del archivo de la base de datos, instanciarás tu aplicación Flask y configurarás y conectarás tu aplicación con SQLAlchemy. Agrega el siguiente código:

flask_app/app.py

basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)

Aquí, construyes una ruta para tu archivo de base de datos SQLite. Primero defines un directorio base como el directorio actual. Utilizas la función os.path.abspath() para obtener la ruta absoluta del directorio del archivo actual. La variable especial __file__ contiene la ruta del archivo app.py actual. Almacenas la ruta absoluta del directorio base en una variable llamada basedir.

Luego creas una instancia de aplicación Flask llamada app, que utilizas para configurar dos claves de configuración de Flask-SQLAlchemy :

  • SQLALCHEMY_DATABASE_URI: El URI de la base de datos para especificar la base de datos con la que deseas establecer una conexión. En este caso, el URI sigue el formato sqlite:///ruta/a/database.db. Utilizas la función os.path.join() para unir inteligentemente el directorio base que construiste y almacenaste en la variable basedir, y el nombre del archivo database.db. Esto se conectará a un archivo de base de datos database.db en tu directorio flask_app. El archivo se creará una vez que inicies la base de datos.

  • SQLALCHEMY_TRACK_MODIFICATIONS: Una configuración para habilitar o deshabilitar el seguimiento de modificaciones de objetos. Se establece en False para deshabilitar el seguimiento y utilizar menos memoria. Para más información, consulte la página de configuración en la documentación de Flask-SQLAlchemy.

Nota:

Si desea utilizar otro motor de base de datos como PostgreSQL o MySQL, deberá utilizar la URI adecuada.

Para PostgreSQL, utilice el siguiente formato:

postgresql://username:password@host:port/database_name

Para MySQL:

mysql://username:password@host:port/database_name

Para más información, consulta la documentación de SQLAlchemy sobre configuración del motor.

Después de configurar SQLAlchemy estableciendo un URI de base de datos y desactivando el seguimiento, crea un objeto de base de datos utilizando la clase SQLAlchemy, pasando la instancia de la aplicación para conectar tu aplicación Flask con SQLAlchemy. Almacena tu objeto de base de datos en una variable llamada db. Utilizarás este objeto db para interactuar con tu base de datos.

Declaración de la tabla

Con la conexión a la base de datos establecida y el objeto de base de datos creado, utilizarás el objeto de base de datos para crear una tabla de base de datos para los estudiantes, que está representada por un modelo — una clase Python que hereda de una clase base que Flask-SQLAlchemy proporciona a través de la instancia de base de datos db que creaste anteriormente. Para definir una tabla de estudiantes como un modelo, agrega la siguiente clase a tu archivo app.py:

flask_app/app.py
# ...

class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    age = db.Column(db.Integer)
    created_at = db.Column(db.DateTime(timezone=True),
                           server_default=func.now())
    bio = db.Column(db.Text)

    def __repr__(self):
        return f'<Student {self.firstname}>'

Aquí, creas un modelo Student, que hereda de la clase db.Model. Esto representa la tabla de estudiantes. Utilizas la clase db.Column para definir columnas para tu tabla. El primer argumento representa el tipo de columna, y los argumentos adicionales representan la configuración de la columna.

Defines las siguientes columnas para el modelo Estudiante:

  • id: El ID del estudiante. Se define como un entero con db.Integer. primary_key=True define esta columna como una clave primaria, lo que le asignará un valor único por la base de datos para cada entrada (es decir, cada estudiante).
  • firstname: El nombre del estudiante. Una cadena con una longitud máxima de 100 caracteres. nullable=False significa que esta columna no debe estar vacía.
  • lastname: El apellido del estudiante. Una cadena con una longitud máxima de 100 caracteres. nullable=False significa que esta columna no debe estar vacía.
  • email: El correo electrónico del estudiante. Una cadena con una longitud máxima de 80 caracteres. unique=True significa que cada correo electrónico debe ser único para cada estudiante. nullable=False significa que esta columna no debe estar vacía.
  • age: La edad del estudiante.
  • created_at: La hora en que se creó el registro del estudiante en la base de datos. Se utiliza db.DateTime para definirlo como un objeto datetime de Python. timezone=True habilita el soporte para zonas horarias. server_default establece el valor predeterminado en la base de datos al crear la tabla, de modo que los valores predeterminados son manejados por la base de datos en lugar del modelo. Se le pasa la función func.now() que llama a la función datetime now() de SQL. En SQLite, se representa como CURRENT_TIMESTAMP al crear la tabla de estudiantes.
  • bio: La biografía del estudiante. db.Text() indica que la columna contiene textos largos.

Consulte la documentación de SQLAlchemy para conocer tipos de columnas distintos a los utilizados en el bloque de código anterior.

La función especial __repr__ permite dar a cada objeto una representación de cadena para reconocerlo con fines de depuración. En este caso, se utiliza el nombre del estudiante.

El archivo app.py ahora se verá de la siguiente manera:

flask_app/app.py
import os
from flask import Flask, render_template, request, url_for, redirect
from flask_sqlalchemy import SQLAlchemy

from sqlalchemy.sql import func


basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\
        'sqlite:///' + os.path.join(basedir, 'database.db')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)


class Student(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    firstname = db.Column(db.String(100), nullable=False)
    lastname = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(80), unique=True, nullable=False)
    age = db.Column(db.Integer)
    created_at = db.Column(db.DateTime(timezone=True),
                           server_default=func.now())
    bio = db.Column(db.Text)

    def __repr__(self):
        return f'<Student {self.firstname}>'

Guarde y cierre app.py.

Creación de la base de datos

Ahora que has establecido la conexión a la base de datos y el modelo de estudiante, usarás la terminal de Flask para crear tu base de datos y tu tabla de estudiantes basada en el modelo Student.

Con tu entorno virtual activado, establece el archivo app.py como tu aplicación Flask usando la variable de entorno FLASK_APP. Luego abre la terminal de Flask usando el siguiente comando en tu directorio flask_app:

  1. export FLASK_APP=app
  2. flask shell

A Python interactive shell will be opened. This special shell runs commands in the context of your Flask application, so that the Flask-SQLAlchemy functions you’ll call are connected to your application.

Importa el objeto de la base de datos y el modelo de estudiante, y luego ejecuta la función db.create_all() para crear las tablas asociadas con tus modelos. En este caso, solo tienes un modelo, lo que significa que la llamada a la función solo creará una tabla en tu base de datos:

  1. from app import db, Student
  2. db.create_all()

Deja la terminal ejecutándose, abre otra ventana de terminal y navega hasta tu directorio flask_app. Ahora verás un nuevo archivo llamado database.db en flask_app.

Nota:

La función db.create_all() no recrea ni actualiza una tabla si ya existe. Por ejemplo, si modificas tu modelo agregando una nueva columna y ejecutas la función db.create_all(), el cambio que hagas en el modelo no se aplicará a la tabla si esta ya existe en la base de datos. La solución es eliminar todas las tablas existentes en la base de datos con la función db.drop_all() y luego recrearlas con la función db.create_all() de la siguiente manera:

  1. db.drop_all()
  2. db.create_all()

Esto aplicará las modificaciones que hagas a tus modelos, pero también eliminará todos los datos existentes en la base de datos. Para actualizar la base de datos y preservar los datos existentes, necesitarás usar migración de esquema, lo cual te permite modificar tus tablas y preservar los datos. Puedes usar la extensión Flask-Migrate para realizar migraciones de esquema de SQLAlchemy a través de la interfaz de línea de comandos de Flask.

Si recibes un error, asegúrate de que la URI de tu base de datos y la declaración de tu modelo sean correctas.

Populando la tabla

Después de crear la base de datos y la tabla de estudiantes, usarás la consola de Flask para agregar algunos estudiantes a tu base de datos a través del modelo Student.

Utiliza la misma consola de Flask que abriste anteriormente, o abre una nueva con tu entorno virtual activado en tu directorio flask_app.

  1. flask shell

Para agregar un estudiante a tu base de datos, importarás el objeto de la base de datos y el modelo Student, y crearás una instancia del modelo Student, pasándole los datos del estudiante mediante argumentos de palabra clave de la siguiente manera:

  1. from app import db, Student
  2. student_john = Student(firstname='john', lastname='doe',
  3. email='[email protected]', age=23,
  4. bio='Biology student')

El objeto student_john representa a un estudiante que se agregará a la base de datos, pero este objeto aún no se ha escrito en la base de datos. Consulta el objeto en la terminal de Flask para ver su cadena de representación que construiste con el método __repr__():

  1. student_john

Recibirás la siguiente salida:

Output
<Student john>

Puedes obtener el valor de las columnas usando los atributos de clase que definiste en el modelo Student:

  1. student_john.firstname
  2. student_john.bio
Output
'john' 'Biology student'

Como este estudiante aún no se ha agregado a la base de datos, su ID será None:

  1. print(student_john.id)
Output
None

Para agregar este estudiante a la base de datos, primero deberás agregarlo a una sesión de base de datos, que gestiona una transacción de base de datos. Flask-SQLAlchemy proporciona el objeto db.session a través del cual puedes gestionar los cambios en tu base de datos. Agrega el objeto student_john a la sesión usando el método db.session.add() para prepararlo para ser escrito en la base de datos:

  1. db.session.add(student_john)

Esto emitirá una declaración INSERT, pero no obtendrás un ID de vuelta porque la transacción de base de datos aún no se ha confirmado. Para confirmar la transacción y aplicar el cambio a la base de datos, usa el método db.session.commit():

  1. db.session.commit()

Ahora que el estudiante John se ha agregado a la base de datos, puedes obtener su ID:

  1. print(student_john.id)
Output
1

También puedes usar el método db.session.add() para editar un elemento en la base de datos. Por ejemplo, puedes modificar el correo electrónico del estudiante de la siguiente manera:

  1. student_john.email = '[email protected]'
  2. db.session.add(student_john)
  3. db.session.commit()

Use el shell de Flask para agregar unos cuantos estudiantes más a tu base de datos:

  1. sammy = Student(firstname='Sammy',
  2. lastname='Shark',
  3. email='[email protected]',
  4. age=20,
  5. bio='Marine biology student')
  6. carl = Student(firstname='Carl',
  7. lastname='White',
  8. email='[email protected]',
  9. age=22,
  10. bio='Marine geology student')
  11. db.session.add(sammy)
  12. db.session.add(carl)
  13. db.session.commit()

Ahora, puedes consultar todos los registros en la tabla de estudiantes usando el atributo query con el método all():

  1. Student.query.all()

Recibirás la siguiente salida:

Output
[<Student john>, <Student Sammy>, <Student Carl>]

En este punto, tienes tres estudiantes en tu base de datos. A continuación, crearás una ruta Flask para la página de índice y mostrarás todos los estudiantes de tu base de datos en ella.

Paso 3 — Mostrar Todos los Registros

En este paso, crearás una ruta y una plantilla para mostrar todos los estudiantes en la base de datos en la página de índice.

Deja el shell de Flask ejecutándose y abre una nueva ventana de terminal.

Abre tu archivo app.py para agregar una ruta para la página de índice:

  1. nano app.py

Agrega la siguiente ruta al final del archivo:

flask_app/app.py

# ...

@app.route('/')
def index():
    students = Student.query.all()
    return render_template('index.html', students=students)

Guarda y cierra el archivo.

Aquí, creas una función de vista index() utilizando el decorador app.route(). En esta función, consultas la base de datos y obtienes todos los estudiantes usando el modelo Student con el atributo query, que te permite recuperar uno o más elementos de la base de datos usando diferentes métodos. Utilizas el método all() para obtener todas las entradas de estudiantes en la base de datos. Almacenas el resultado de la consulta en una variable llamada students y la pasas a una plantilla llamada index.html que renderizas utilizando la función auxiliar render_template().

Antes de crear el archivo de plantilla index.html en el que mostrarás los estudiantes existentes en la base de datos, primero crearás una plantilla base, que tendrá todo el código HTML básico que otras plantillas también usarán para evitar la repetición de código. Luego crearás el archivo de plantilla index.html que renderizaste en tu función index(). Para obtener más información sobre las plantillas, consulta Cómo Usar Plantillas en una Aplicación Flask.

Crea un directorio templates, luego abre una nueva plantilla llamada base.html:

  1. mkdir templates
  2. nano templates/base.html

Agrega el siguiente código dentro del archivo base.html:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .title {
            margin: 5px;
        }

        .content {
            margin: 5px;
            width: 100%;
            display: flex;
            flex-direction: row;
            flex-wrap: wrap;
        }

        .student {
            flex: 20%;
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3;
            inline-size: 100%;
        }

        .bio {
            padding: 10px;
            margin: 5px;
            background-color: #ffffff;
            color: #004835;
        }

        .name a {
            color: #00a36f;
            text-decoration: none;
        }

        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Guarda y cierra el archivo.

Esta plantilla base tiene todo el esquema HTML que necesitarás reutilizar en tus otras plantillas. El bloque title será reemplazado para establecer un título para cada página, y el bloque content será reemplazado con el contenido de cada página. La barra de navegación tiene tres enlaces: uno para la página de índice, que enlaza con la función de vista index() usando la función auxiliar url_for(), uno para una página de Crear, y uno para una página Acerca de si decides agregarla a tu aplicación. Editarás este archivo más tarde después de agregar una página para crear nuevos estudiantes para hacer que el enlace de Crear sea funcional.

A continuación, abre un nuevo archivo de plantilla index.html. Esta es la plantilla a la que haces referencia en el archivo app.py:

  1. nano templates/index.html

Agrega el siguiente código a él:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1 class="title">{% block title %} Students {% endblock %}</h1>
    <div class="content">
        {% for student in students %}
            <div class="student">
                <p><b>#{{ student.id }}</b></p>
                <b>
                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
                </b>
                <p>{{ student.email }}</p>
                <p>{{ student.age }} years old.</p>
                <p>Joined: {{ student.created_at }}</p>
                <div class="bio">
                    <h4>Bio</h4>
                    <p>{{ student.bio }}</p>
                </div>
            </div>
        {% endfor %}
    </div>
{% endblock %}

Guarda y cierra el archivo.

Aquí, extiendes la plantilla base y reemplazas el contenido del bloque de contenido. Utilizas un encabezado <h1> que también sirve como título. Utilizas un bucle for de Jinja en la línea {% for student in students %} para recorrer cada estudiante en la variable students que pasaste desde la función de vista index() a esta plantilla. Muestras el ID del estudiante, su nombre y apellido, correo electrónico, edad, la fecha en que fueron agregados a la base de datos y su biografía.

Mientras estés en tu directorio flask_app con tu entorno virtual activado, indica a Flask acerca de la aplicación (app.py en este caso) usando la variable de entorno FLASK_APP. Luego, establece la variable de entorno FLASK_ENV en development para ejecutar la aplicación en modo de desarrollo y obtener acceso al depurador. Para obtener más información sobre el depurador de Flask, consulta Cómo Manejar Errores en una Aplicación Flask. Utiliza los siguientes comandos para hacerlo:

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

A continuación, ejecuta la aplicación:

  1. flask run

Con el servidor de desarrollo en funcionamiento, visita la siguiente URL usando tu navegador:

http://127.0.0.1:5000/

Verás los estudiantes que has agregado a la base de datos en una página similar a la siguiente:

Has mostrado los estudiantes que tienes en tu base de datos en la página de índice. A continuación, crearás una ruta para una página de estudiante, donde podrás mostrar los detalles de cada estudiante individual.

Paso 4 — Mostrar un Único Registro

En este paso, usarás el shell de Flask para consultar estudiantes por su ID, y crearás una ruta y una plantilla para mostrar los detalles de cada estudiante en una página dedicada.

Al final de este paso, la URL http://127.0.0.1:5000/1 será una página que muestra al primer estudiante (porque tiene el ID 1). La URL http://127.0.0.1:5000/ID mostrará la publicación con el número de ID asociado, si existe.

Deje el servidor de desarrollo en ejecución y abra una nueva ventana de terminal.

Abra la terminal de Flask para una demostración de cómo consultar estudiantes:

  1. flask shell

Para consultar registros y recuperar datos de la base de datos, Flask-SQLAlchemy proporciona un atributo query en la clase del modelo. Puede usar sus métodos para obtener registros con un filtro específico.

Por ejemplo, puede usar el método filter_by() con un parámetro como firstname que coincida con una columna en la tabla con un argumento para recuperar un estudiante específico:

  1. from app import db, Student
  2. Student.query.filter_by(firstname='Sammy').all()
Output
[<Student Sammy>]

Aquí recuperas todos los estudiantes con Sammy como su primer nombre. Utilizas el método all() para obtener una lista de todos los resultados. Para obtener el primer resultado, que es el único resultado aquí, puedes usar el método first():

  1. Student.query.filter_by(firstname='Sammy').first()
Output
<Student Sammy>

Para obtener un estudiante por su ID, puedes usar filter_by(id=ID):

  1. Student.query.filter_by(id=3).first()

O, puedes usar el método más corto get(), que te permite recuperar un artículo específico usando su clave primaria:

  1. Student.query.get(3)

Ambos darán el mismo resultado:

Output
<Student Carl>

Ahora puedes salir de la terminal:

  1. exit()

Para recuperar a un estudiante por su ID, crearás una nueva ruta que renderice una página para cada estudiante individual. Utilizarás el método get_or_404() que proporciona Flask-SQLAlchemy, el cual es una variante del método get(). La diferencia es que get() devuelve el valor None cuando no hay ningún resultado que coincida con el ID dado, y get_or_404() devuelve una respuesta HTTP 404 Not Found. Abre app.py para su modificación:

  1. nano app.py

Agrega la siguiente ruta al final del archivo:

flask_app/app.py
# ...

@app.route('/<int:student_id>/')
def student(student_id):
    student = Student.query.get_or_404(student_id)
    return render_template('student.html', student=student)

Guarda y cierra el archivo.

Aquí, usas la ruta '/<int:student_id>/', con int: siendo un convertidor que convierte la cadena predeterminada en la URL en un entero. Y student_id es la variable de URL que determinará el estudiante que se mostrará en la página.

El ID se pasa desde la URL a la función de vista student() a través del parámetro student_id. Dentro de la función, consultas la colección de estudiantes y recuperas un estudiante por el ID utilizando el método get_or_404(). Esto guardará los datos del estudiante en la variable student si existe, y responderá con un error HTTP 404 Not Found si no existe ningún estudiante con el ID dado en la base de datos.

Renderizas una plantilla llamada student.html y le pasas el estudiante que recuperaste.

Abre este nuevo archivo de plantilla student.html:

  1. nano templates/student.html

Escribe el siguiente código en este nuevo archivo student.html. Esto será similar a la plantilla index.html, excepto que solo mostrará a un estudiante:

flask_app/templates/student.html
{% extends 'base.html' %}

{% block content %}
    <span class="title">
        <h1>{% block title %} {{ student.firstname }} {{ student.lastname }}{% endblock %}</h1>
    </span>
    <div class="content">
            <div class="student">
                <p><b>#{{ student.id }}</b></p>
                <b>
                    <p class="name">{{ student.firstname }} {{ student.lastname }}</p>
                </b>
                <p>{{ student.email }}</p>
                <p>{{ student.age }} years old.</p>
                <p>Joined: {{ student.created_at }}</p>
                <div class="bio">
                    <h4>Bio</h4>
                    <p>{{ student.bio }}</p>
                </div>
            </div>
    </div>
{% endblock %}

Guarda y cierra el archivo.

En este archivo, extiendes la plantilla base, estableciendo el nombre completo del estudiante como título de la página. Muestra el ID del estudiante, el nombre y apellido del estudiante, correo electrónico, edad, la fecha de creación del registro y su biografía.

Utiliza tu navegador para navegar a la URL del segundo estudiante:

http://127.0.0.1:5000/2

Verás una página similar a la siguiente:

Ahora, edita index.html para que cada nombre de estudiante enlace a su página:

  1. nano templates/index.html

Edita el bucle for de la siguiente manera:

flask_app/templates/index.html
{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
    </div>
{% endfor %}

Guarda y cierra el archivo.

Agregaste una etiqueta <a> al nombre completo del estudiante que enlaza a la página del estudiante usando la función url_for(), pasando el ID del estudiante que está almacenado en student.id a la función de vista student().

Navega a tu página de índice o actualízala:

http://127.0.0.1:5000/

Ahora verás que cada nombre de estudiante enlaza a la página correcta del estudiante.

Después de crear una página para estudiantes individuales, a continuación agregarás una página para agregar nuevos estudiantes a la base de datos.

Paso 5 — Creando un Nuevo Registro

En este paso, agregarás una nueva ruta a tu aplicación para añadir nuevos estudiantes a la base de datos utilizando formularios web.

Renderizarás una página con un formulario web donde los usuarios ingresarán los datos del estudiante. Luego manejarás la presentación del formulario, crearás un objeto para el nuevo estudiante utilizando el modelo Student, lo añadirás a la sesión y luego confirmarás la transacción, similar a cómo has añadido entradas de estudiantes en el Paso 2.

Deja el servidor de desarrollo en ejecución y abre una nueva ventana de terminal.

Primero, abre tu archivo app.py:

  1. nano app.py

Agrega la siguiente ruta al final del archivo app.py:

flask_app/app.py
# ...


@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

Guarda y cierra el archivo.

En esta ruta, pasas la tupla ('GET', 'POST') al parámetro methods para permitir tanto las peticiones GET como POST. Las peticiones GET se utilizan para recuperar datos del servidor. Las peticiones POST se utilizan para enviar datos a una ruta específica. Por defecto, solo se permiten las peticiones GET. Cuando el usuario solicita por primera vez la ruta /create utilizando una petición GET, se renderizará un archivo de plantilla llamado create.html. Más adelante editarás esta ruta para manejar las peticiones POST cuando los usuarios completen y envíen el formulario web para añadir nuevos estudiantes.

Abre la nueva plantilla create.html:

  1. nano templates/create.html

Agrega el siguiente código a ella:

{% extends 'base.html' %}

{% block content %}
    <h1 style="width: 100%">{% block title %} Add a New Student {% endblock %}</h1>
    <form method="post">
        <p>
            <label for="firstname">First Name</label>
            <input type="text" name="firstname"
                   placeholder="First name">
            </input>
        </p>

        <p>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname"
                   placeholder="Last name">
            </input>
        </p>

        <p>
            <label for="email">Email</label>
            <input type="email" name="email"
                   placeholder="Student email">
            </input>
        </p>

        <p>
            <label for="age">Age</label>
            <input type="number" name="age"
                   placeholder="Age">
            </input>
        </p>

        <p>
        <label for="bio">Bio</label>
        <br>
        <textarea name="bio"
                  placeholder="Bio"
                  rows="15"
                  cols="60"
                  ></textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

Guarda y cierra el archivo.

Amplías la plantilla base, estableces un encabezado como título y utilizas una etiqueta <form> con el atributo method establecido en post para indicar que el formulario enviará una solicitud POST.

Tienes dos campos de texto con los nombres firstname y lastname. Usarás estos nombres para acceder a los datos del formulario que el usuario envíe en tu función de vista más adelante.

Tienes un campo de correo electrónico con el nombre email, un campo numérico para la edad del estudiante y un área de texto para la biografía del estudiante.

Por último, tienes un botón Enviar al final del formulario.

Ahora, con el servidor de desarrollo en funcionamiento, usa tu navegador para navegar a la ruta /create:

http://127.0.0.1:5000/create

Verás una página Agregar un Nuevo Estudiante con un formulario web y un botón Enviar de la siguiente manera:

Si completas el formulario y lo envías, enviando una solicitud POST al servidor, no sucede nada porque no manejaste las solicitudes POST en la ruta /create.

Abre app.py para manejar la solicitud POST que envía el usuario:

  1. nano app.py

Edita la ruta /create para que se vea de la siguiente manera:

flask_app/app.py

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        age = int(request.form['age'])
        bio = request.form['bio']
        student = Student(firstname=firstname,
                          lastname=lastname,
                          email=email,
                          age=age,
                          bio=bio)
        db.session.add(student)
        db.session.commit()

        return redirect(url_for('index'))

    return render_template('create.html')

Guarda y cierra el archivo.

Gestionas las solicitudes POST dentro de la condición if request.method == 'POST'. Extraes el nombre, apellido, correo electrónico, edad y biografía que el usuario envía desde el objeto request.form. Conviertes la edad que se pasa como una cadena a un entero usando la función int() de Python. Construyes un objeto student utilizando el modelo Student. Añades el objeto estudiante a la sesión de la base de datos y luego confirmas la transacción.

Por último, rediriges al usuario a la página de índice donde puede ver al nuevo estudiante añadido debajo de los estudiantes existentes.

Con el servidor de desarrollo en ejecución, usa tu navegador para navegar a la ruta /create:

http://127.0.0.1:5000/create

Rellena el formulario con algunos datos y envíalo.

Serás redirigido a la página de índice donde verás a tu nuevo estudiante añadido.

Ahora que tienes la funcionalidad para añadir nuevos estudiantes, necesitarás añadir un enlace a la página Create en la barra de navegación. Abre base.html:

  1. nano templates/base.html

Edita la etiqueta <body> modificando el valor del atributo href para el enlace Create:

flask_app/templates/base.html
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>

Guarda y cierra el archivo.

Actualiza tu página de índice y notarás que el enlace Create en la barra de navegación ahora es funcional.

Ahora tienes una página con un formulario web para agregar nuevos estudiantes. Para obtener más información sobre formularios web, consulta Cómo Usar Formularios Web en una Aplicación Flask. Para un método más avanzado y seguro para gestionar formularios web, consulta Cómo Usar y Validar Formularios Web con Flask-WTF. A continuación, agregarás una página para editar los datos de los estudiantes existentes.

Paso 6 — Editar un Registro

En este paso, agregarás una nueva página a tu aplicación para editar los datos de estudiantes existentes. Agregarás una nueva ruta /ID/edit/ para editar los datos de estudiantes según su ID.

Abre app.py:

  1. nano app.py

Agrega la siguiente ruta al final del archivo. Esto obtiene la entrada del estudiante que deseas editar utilizando su ID. Extrae los nuevos datos del estudiante enviados a través de un formulario web que crearás más adelante. Luego edita los datos del estudiante y redirige al usuario a la página de índice:

flask_app/app.py
# ...


@app.route('/<int:student_id>/edit/', methods=('GET', 'POST'))
def edit(student_id):
    student = Student.query.get_or_404(student_id)

    if request.method == 'POST':
        firstname = request.form['firstname']
        lastname = request.form['lastname']
        email = request.form['email']
        age = int(request.form['age'])
        bio = request.form['bio']

        student.firstname = firstname
        student.lastname = lastname
        student.email = email
        student.age = age
        student.bio = bio

        db.session.add(student)
        db.session.commit()

        return redirect(url_for('index'))

    return render_template('edit.html', student=student)

Guarda y cierra el archivo.

Aquí tienes la ruta /<int:student_id>/edit/ que acepta tanto los métodos POST como GET, con student_id como una variable de URL que pasa el ID a la función de vista edit().

Utiliza el método de consulta get_or_404() en el modelo Student para obtener al estudiante asociado con el ID de estudiante dado. Esto responderá con un error 404 Not Found en caso de que no exista ningún estudiante con el ID dado en la base de datos.

Si el ID dado tiene un estudiante asociado, la ejecución del código continúa hacia la condición if request.method == 'POST'. Si la solicitud fue una solicitud GET, lo que significa que el usuario no envió un formulario, entonces esta condición es falsa y el código dentro de ella se omitirá hasta la línea return render_template('edit.html', student=student). Esto renderiza una plantilla edit.html, pasándole el objeto estudiante que obtuviste de la base de datos, permitiéndote llenar el formulario web del estudiante con los datos actuales del estudiante. Crearás esta plantilla edit.html más tarde.

Cuando un usuario edita los datos del estudiante y envía el formulario, se ejecuta el código dentro del if request.method == 'POST'. Extraes los datos del estudiante enviados del objeto request.form en variables correspondientes. Estableces cada atributo del objeto student a los datos recién enviados para cambiar los valores de las columnas como lo has hecho en el Paso 2. Si no se realizó ningún cambio en un campo en el formulario web, el valor de esa columna permanecerá igual en la base de datos.

Después de establecer los datos del estudiante a los datos recién enviados, agregas el objeto student a la sesión de la base de datos, luego confirmas los cambios. Por último, rediriges al usuario a la página de índice.

A continuación, necesitas crear una página donde los usuarios puedan hacer la edición. Abre una nueva plantilla edit.html:

  1. nano templates/edit.html

Este nuevo archivo tendrá un formulario web similar al que está en el archivo create.html con los datos actuales del estudiante como valores predeterminados para los campos. Agrega el siguiente código dentro de él:

flask_app/templates/edit.html

{% extends 'base.html' %}

{% block content %}
    <h1 style="width: 100%">
        {% block title %} Edit {{ student.firstname }}
                               {{ student.lastname }}'s Details
        {% endblock %}
    </h1>
    <form method="post">
        <p>
            <label for="firstname">First Name</label>
            <input type="text" name="firstname"
                   value={{ student.firstname }}
                   placeholder="First name">
            </input>
        </p>

        <p>
            <label for="lastname">Last Name</label>
            <input type="text" name="lastname"
                   value={{ student.lastname }}
                   placeholder="Last name">
            </input>
        </p>

        <p>
            <label for="email">Email</label>
            <input type="email" name="email"
                   value={{ student.email }}
                   placeholder="Student email">
            </input>
        </p>

        <p>
            <label for="age">Age</label>
            <input type="number" name="age"
                   value={{ student.age }}
                   placeholder="Age">
            </input>
        </p>

        <p>
        <label for="bio">Bio</label>
        <br>
        <textarea name="bio"
                  placeholder="Bio"
                  rows="15"
                  cols="60"
                  >{{ student.bio }}</textarea>
        </p>
        <p>
            <button type="submit">Submit</button>
        </p>
    </form>
{% endblock %}

Guarda y cierra el archivo.

El título tiene el nombre y apellido del estudiante. El atributo value de cada campo de entrada y el valor del área de texto de la biografía están configurados con el valor correspondiente en el objeto student que pasaste desde la función edit() a la plantilla edit.html.

Ahora, navega a la siguiente URL para editar los detalles del primer estudiante:

http://127.0.0.1:5000/1/edit

Verás una página similar a la siguiente:

Edita los datos del estudiante y envía el formulario. Serás redirigido a la página de índice, y la información del estudiante se actualizará.

A continuación, agregarás un botón Editar debajo de cada estudiante en la página de índice para enlazar a su página de edición. Abre el archivo de plantilla index.html:

  1. nano templates/index.html

Edita el bucle for en este archivo index.html para que se vea exactamente como sigue:

flask_app/templates/index.html

{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>
    </div>
{% endfor %}

Guarda y cierra el archivo.

Aquí agregas una etiqueta <a> para enlazar a la función de vista edit(), pasando el valor student.id para enlazar a la página de edición de cada estudiante con un enlace Editar.

Ahora tienes una página para editar estudiantes existentes. A continuación, agregarás un botón Eliminar para eliminar estudiantes de la base de datos.

Paso 7 — Eliminar un registro

En este paso, agregarás una nueva ruta y un botón Eliminar para eliminar estudiantes existentes.

Primero, agregarás una nueva ruta /id/delete que acepta solicitudes POST. Tu nueva función de vista delete() recibirá el ID del estudiante que deseas eliminar, pasará el ID al método de consulta get_or_404() en el modelo Student para obtenerlo si existe, o responderá con una página 404 Not Found si no se encontró ningún estudiante con el ID dado en la base de datos.

Abre app.py para editarlo:

  1. nano app.py

Agrega la siguiente ruta al final del archivo:

flask_app/app.py

# ...

@app.post('/<int:student_id>/delete/')
def delete(student_id):
    student = Student.query.get_or_404(student_id)
    db.session.delete(student)
    db.session.commit()
    return redirect(url_for('index'))

Guarda y cierra el archivo.

Aquí, en lugar de usar el decorador app.route habitual, utilizas el decorador app.post introducido en Flask versión 2.0.0, que agregó atajos para métodos HTTP comunes. Por ejemplo, @app.post("/login") es un atajo para @app.route("/login", methods=["POST"]). Esto significa que esta función de vista solo acepta solicitudes POST, y al navegar a la ruta /ID/delete en tu navegador, devolverá un error 405 Método no permitido, porque los navegadores web por defecto realizan solicitudes GET. Para eliminar un estudiante, el usuario hace clic en un botón que envía una solicitud POST a esta ruta.

Esta función de vista delete() recibe el ID del estudiante a eliminar a través de la variable de URL student_id. Utilizas el método get_or_404() para obtener un estudiante y guardarlo en una variable student, o responder con un 404 No Encontrado en caso de que el estudiante no exista. Utilizas el método delete() en la sesión de la base de datos en la línea db.session.delete(student), pasándole el objeto del estudiante. Esto configura la sesión para eliminar el estudiante cada vez que se confirma la transacción. Como no necesitas realizar ninguna otra modificación, comprometes directamente la transacción usando db.session.commit(). Por último, rediriges al usuario a la página de índice.

A continuación, edita la plantilla index.html para agregar un Botón Eliminar Estudiante:

  1. nano templates/index.html

Edita el bucle for añadiendo una nueva etiqueta <form> directamente debajo del enlace Editar:

flask_app/templates/index.html

{% for student in students %}
    <div class="student">
        <p><b>#{{ student.id }}</b></p>
        <b>
            <p class="name">
                <a href="{{ url_for('student', student_id=student.id)}}">
                    {{ student.firstname }} {{ student.lastname }}
                </a>
            </p>
        </b>
        <p>{{ student.email }}</p>
        <p>{{ student.age }} years old.</p>
        <p>Joined: {{ student.created_at }}</p>
        <div class="bio">
            <h4>Bio</h4>
            <p>{{ student.bio }}</p>
        </div>
        <a href="{{ url_for('edit', student_id=student.id) }}">Edit</a>

        <hr>
        <form method="POST"
                action="{{ url_for('delete', student_id=student.id) }}">
            <input type="submit" value="Delete Student"
                onclick="return confirm('Are you sure you want to delete this entry?')">
        </form>

    </div>
{% endfor %}

Guarda y cierra el archivo.

Aquí, tienes un formulario web que envía una solicitud POST a la función de vista delete(). Pasas student.id como argumento para el parámetro student_id para especificar la entrada del estudiante que se eliminará. Utilizas la función confirm() disponible en los navegadores web para mostrar un mensaje de confirmación antes de enviar la solicitud.

Ahora actualiza tu página de índice.

Verás un botón Eliminar Estudiante debajo de cada entrada de estudiante. Haz clic en él y confirma la eliminación. Serás redirigido a la página de índice y el estudiante ya no estará allí.

Ahora tienes una forma de eliminar estudiantes de la base de datos en tu aplicación de gestión de estudiantes.

Conclusión

Has construido una pequeña aplicación web Flask para gestionar estudiantes utilizando Flask y Flask-SQLAlchemy con una base de datos SQLite. Aprendiste cómo conectarte a tu base de datos, configurar modelos de base de datos que representan tus tablas, añadir elementos a tu base de datos, consultar tu tabla y modificar datos de la base de datos.

Usar SQLAlchemy en tu aplicación te permite utilizar clases y objetos de Python para gestionar tu base de datos SQL. En lugar de SQLite, puedes utilizar otro motor de base de datos, y aparte de la configuración SQLALCHEMY_DATABASE_URI responsable de la conexión, no necesitas cambiar nada en el código principal de tu aplicación. Eso te permite cambiar de un motor de base de datos SQL a otro con cambios mínimos en el código. Consulta la documentación de Flask-SQLAlchemy para obtener más información.

Si deseas leer más sobre Flask, consulta los otros tutoriales en la serie Cómo Construir Aplicaciones Web con Flask.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-flask-sqlalchemy-to-interact-with-databases-in-a-flask-application