Vistas y Blueprint en Flask

vistas-y-blueprint-en-flask Escrito por @gnuxdar   Publicado 23/06/2023

Blueprints y vistas
    Una función de vista es el código que escribimos para responder a las solicitudes de nuestra aplicación. Flask utiliza patrones para hacer coincidir la URL de solicitud entrante con la vista que debe manejarla. La vista devuelve datos que Flask convierte en una respuesta saliente. Flask también puede hacer lo contrario y generar una URL a una vista basada en su nombre y argumentos.

 

Crear un Blueprint

Un Blueprint es una forma de organizar un grupo de vistas y otro código relacionado. En lugar de registrar vistas y otro código directamente en una aplicación, se registran con un Blueprint. Luego, el Blueprint se registra en la aplicación cuando está disponible en la función de fábrica.
Flask_todolist tendrá dos Blueprints, uno para funciones de autenticación y otro para funciones de publicaciones de items de la lista. El código para cada Blueprint se colocará en un módulo separado. Dado que el “Todo List” necesita conocer la autenticación, primero escribirás el Blueprint de autenticación.


flask_todolist/auth.py

import functools
from flask import (
   Blueprint, flash, g, redirect, render_template, request, session, url_for
)
from werkzeug.security import check_password_hash, generate_password_hash
from flask_todolist.db import get_db
bp = Blueprint('auth', __name__, url_prefix='/auth')


Esto crea un Blueprint llamado 'auth'. Al igual que el objeto de la aplicación, el Blueprint necesita saber dónde se define, por lo que se pasa __name__ como segundo argumento. El url_prefix se añadirá al comienzo de todas las URL asociadas con el Blueprint.
Importa y registra el Blueprint desde la función de fábrica utilizando app.register_blueprint(). Coloca el nuevo código al final de la función de fábrica antes de devolver la aplicación.


flask_todolist/__init__.py

def create_app():
   app = ...
   # existing code omitted
   from . import auth
   app.register_blueprint(auth.bp)
   return app

 

El Blueprint de autenticación tendrá vistas para registrar nuevos usuarios, iniciar sesión y cerrar sesión.

 

La primera vista: Register

Cuando el usuario visita la URL /auth/register, la vista de registro devolverá HTML con un formulario para que lo completen. Cuando envíen el formulario, se validará su entrada y se mostrará nuevamente el formulario con un mensaje de error o se creará un nuevo usuario y se dirigirá a la página de inicio de sesión.
Por ahora solo escribirás el código de la vista. En la siguiente página, escribirás plantillas para generar el formulario HTML.


flask_todolist/auth.py

@bp.route('/register', methods=('GET', 'POST'))
def register():
   if request.method == 'POST':
       username = request.form['username']
       password = request.form['password']
       db = get_db()
       error = None
       if not username:
           error = 'Username is required.'
       elif not password:
           error = 'Password is required.'
       if error is None:
           try:
               db.execute(
                   "INSERT INTO user (username, password) VALUES (?, ?)",
                   (username, generate_password_hash(password)),
               )
               db.commit()
           except db.IntegrityError:
               error = f"User {username} is already registered."
           else:
               return redirect(url_for("auth.login"))
       flash(error)
   return render_template('auth/register.html')

 

Aquí está lo que hace la función de la vista de registro:

  1. @bp.route asocia la URL /register con la función de vista register. Cuando Flask recibe una solicitud a /auth/register, llamará a la vista register y utilizará el valor de retorno como respuesta.
  2. Si el usuario envió el formulario, request.method será POST'. En este caso, comienza a validar la entrada.
  3. request.form es un tipo especial de diccionario que mapea las claves y los valores enviados en el formulario. El usuario ingresará su nombre de usuario y contraseña.
  4. Valida que el nombre de usuario y la contraseña no estén vacíos.
  5. Si la validación tiene éxito, inserta los datos del nuevo usuario en la base de datos.
    • db.execute toma una consulta SQL con marcadores de posición ? para cualquier entrada del usuario, y una tupla de valores para reemplazar los marcadores de posición. La biblioteca de la base de datos se encargará de escapar los valores para que no estés vulnerable a un ataque de inyección de SQL.
    • Por seguridad, las contraseñas nunca deben almacenarse directamente en la base de datos. En su lugar, se utiliza generate_password_hash() para generar un hash seguro de la contraseña, y ese hash se almacena. Dado que esta consulta modifica datos, es necesario llamar a db.commit() después para guardar los cambios.
    • Ocurrirá un sqlite3.IntegrityError si el nombre de usuario ya existe, lo cual se mostrará al usuario como otro error de validación.
  6. Después de almacenar el usuario, se redirige a la página de inicio de sesión. url_for() genera la URL para la vista de inicio de sesión según su nombre. Esto es preferible a escribir directamente la URL, ya que te permite cambiar la URL más adelante sin modificar todo el código que hace referencia a ella. redirect() genera una respuesta de redireccionamiento a la URL generada.
  7. Si la validación falla, se muestra el error al usuario. flash() almacena mensajes que se pueden recuperar al renderizar la plantilla.
  8. Cuando el usuario navega inicialmente a auth/register, o hubo un error de validación, se debe mostrar una página HTML con el formulario de registro. render_template() renderizará una plantilla que contiene el HTML, que escribirás en el siguiente paso del tutorial.

 

Login
Esta vista sigue el mismo patrón que la vista de registro anterior.


flask_todolist/auth.py

@bp.route('/login', methods=('GET', 'POST'))
def login():
   if request.method == 'POST':
       username = request.form['username']
       password = request.form['password']
       db = get_db()
       error = None
       user = db.execute(
           'SELECT * FROM user WHERE username = ?', (username,)
       ).fetchone()
       if user is None:
           error = 'Incorrect username.'
       elif not check_password_hash(user['password'], password):
           error = 'Incorrect password.'
       if error is None:
           session.clear()
           session['user_id'] = user['id']
           return redirect(url_for('index'))
       flash(error)
   return render_template('auth/login.html')


Hay algunas diferencias con respecto a la vista de registro:

Hay algunas diferencias en la vista de inicio de sesión en comparación con la vista de registro:

  1. Se consulta y almacena al usuario en una variable para su uso posterior.
          fetchone() devuelve una fila de la consulta. Si la consulta no devuelve resultados, devuelve None. Más adelante se usará fetchall(), que devuelve una lista con todos los resultados.
  2. check_password_hash() realiza el hash de la contraseña enviada de la misma manera que el hash almacenado y los compara de forma segura. Si coinciden, la contraseña es válida.
  3. session es un diccionario que almacena datos entre solicitudes. Cuando la validación tiene éxito, se almacena el id del usuario en una nueva sesión. Los datos se almacenan en una cookie que se envía al navegador y el navegador los envía de vuelta en solicitudes posteriores. Flask firma los datos de manera segura para evitar manipulaciones.


Ahora que el id del usuario se almacena en la sesión, estará disponible en solicitudes posteriores. Al comienzo de cada solicitud, si un usuario ha iniciado sesión, su información debe cargarse y ponerse a disposición de otras vistas.


flask_todolist/auth.py

@bp.before_app_request
def load_logged_in_user():
   user_id = session.get('user_id')
   if user_id is None:
       g.user = None
   else:
       g.user = get_db().execute(
           'SELECT * FROM user WHERE id = ?', (user_id,)
       ).fetchone()

 

bp.before_app_request() registra una función que se ejecuta antes de la función de vista, sin importar la URL que se solicite. load_logged_in_user verifica si hay un id de usuario almacenado en la sesión y obtiene los datos de ese usuario desde la base de datos, almacenándolos en g.user, que permanece durante toda la duración de la solicitud. Si no hay un id de usuario, o si el id no existe, g.user será None.

 

Logout
Para cerrar sesión, debes eliminar el id de usuario de la sesión. De esta manera, load_logged_in_user no cargará un usuario en las solicitudes posteriores.


flask_todolist/auth.py

@bp.route('/logout')
def logout():
   session.clear()
   return redirect(url_for('index'))

 

Requerir autenticación en otras vistas
Crear, editar y eliminar publicaciones del “Todo List” requerirá que un usuario inicie sesión. Se puede usar un decorador para verificar esto para cada vista a la que se aplica.


flask_todolist/auth.py

def login_required(view):
   @functools.wraps(view)
   def wrapped_view(**kwargs):
       if g.user is None:
           return redirect(url_for('auth.login'))
       return view(**kwargs)
   return wrapped_view

 

Este decorador devuelve una nueva función de vista que envuelve la vista original a la que se aplica. La nueva función verifica si hay un usuario cargado y, en caso contrario, redirige a la página de inicio de sesión. Si hay un usuario cargado, se llama a la vista original y continúa normalmente. Utilizarás este decorador al escribir las vistas del blog.

 

Endpoints y URLs
La función url_for() genera la URL hacia una vista basada en su nombre y argumentos. El nombre asociado con una vista también se llama punto final (endpoint) y, por defecto, es el mismo que el nombre de la función de la vista.

Por ejemplo, la vista hello() que se agregó a la fábrica de la aplicación anteriormente en el tutorial tiene el nombre 'hello' y se puede enlazar usando url_for('hello'). Si tomara un argumento, como verás más adelante, se podría enlazar usando url_for('hello', who='Mundo').

Cuando se utiliza un blueprint, el nombre del blueprint se agrega al principio del nombre de la función, por lo que el endpoint para la función de inicio de sesión que escribiste arriba es 'auth.login' porque la agregaste al blueprint 'auth'.

 

← Definir y acceder a la base de datos | Continúa con Templates → 



Atras

Últimas Publicaciones

Le puede interesar los ultimos articulos públicados

Como agregar JavaScript Custom en Magento 2 como-agregar-javascript-custom-en-magento-2

En este Post aprenderemos a personalizar la tienda Magento 2. Descubre cómo incorporar JavaScript personalizado para mejorar la funcionalidad y ...

Leer más...
Current version of RDBMS is not supported current-version-of-rdbms-is-not-supported

Current version of RDBMS is not supported. Used Version: 10.6.17-MariaDB-1:10.6.17+maria~ubu2004. Supported versions: MySQL-8, MySQL-5....

Leer más...
Claves para Aprender Desarrollo Web de Manera Efectiva claves-para-aprender-desarrollo-web-de-manera-efectiva

Los principales motivos para aprenderLa motivación es uno de los pilares fundamentales en el proceso de aprendizaje del desarrollo web....

Leer más...
Dominando el Estilo Un Viaje al Mundo de CSS ✨ dominando-el-estilo-un-viaje-al-mundo-de-css

✨ Dominando el Estilo: Un Viaje al Mundo de CSSEn el universo del desarrollo web, CSS (Cascading Style Sheets) desempeña un papel funda...

Leer más...