Flask y MVC: Conceptos e Instalación.

Renuncio a PHP (?). No, la verdad es que sigue siendo mi lenguaje padre, para varios proyectos, especialmente por su facilidad de uso. Sin embargo siempre me interesó Python y como me oriento al desarrollo web, encontre en Flask a mi pastor (nada me faltará). Así que en este post, explicaré algunas cosillas para que puedan crear proyectos con este framework.

Primero que todo: el Patrón MVC.

De un tiempo a esta parte, la web se ha convertido en la principal herramienta para compartir información. A más de 30 años del estreno en sociedad de HTML, todo lo que salió después, orientado a crear verdaderos sistemas, fue evolucionando y estandarizando hasta lo que tenemos hoy, por lo que pronto se hizo necesario, desarrollar formas eficientes para su construcción.

Una de estas fórmulas es el Patron de Arquitectura Modelo-Vista-Controlador. Este es un concepto que pretende a grandes rasgos, separar los datos -Modelo-, de la presentación -Vista- y la lógica de negocio -Controlador-. Es decir, cada "capa" o parte del proyecto, funciona de manera aislada, intercomunicándose entre si, de la siguiente manera.

Si bien existen otros Patrones de arquitectura, la mayoría de los frameworks existentes en el mercado, basan su estructura en este. Brevemente describiré sus componentes.

  • Modelo: Es el que interactúa con los datos. Puede ser incluso utilizado para crear las entidades de datos, sean SQL o No SQL.

  • Vista: La presentación. Aquí el usuario, mediante una Interfaz Gráfica -GUI-, realiza las peticiones y recibe las respuestas.

  • Controlador: La lógica del negocio, donde escribiremos los algoritmos necesarios para el procesamiento, cálculo y otros menesteres. Se encarga de comunicar a la vista, con el modelo. La lógica de programación se pone aquí (Nota: eso no impide que por ejemplo, en el Modelo, también se aplique algo de lógica, pero no es lo recomendable).

Como trabajar MVC con Flask.

Flask es lo que se conoce como micro framework. A diferencia de Django, solo tiene lo necesario para empezar. Es escalable y puede servir para proyectos pequeños y simples a mas grandes y de mayor complejidad. En si mismo, esto da una ventaja, ya que es mas flexible a la hora de trabajar una aplicacion, pero al tener menos dependencias incluidas, puede ser difícil el mantenimiento.
Una aplicación Flask se divide por lo general de una forma muy simple. Tal como en el siguiente esquema.

└── Flask App /  
├── controllers/  
│ └── usuarioController.py  
├── models/  
│ └── usuarioModel.py  
├── utils  
├── templates/  
│ └── index.html  
├── static/  
│ ├── js  
│ └── css  
└── app.py

Por lo genera en los tutoriales de inicio, siempre se hacen todas las funciones y/o métodos en el archivo principal, pero para fines mas didácticos, usaremos la configuración de arriba. para la construcción de la aplicacion de ejemplo.

Podemos observar que se ha separado el controlador y modelo en subdirectorios. Esta es la forma mas correcta de trabajar, ya que así todo esta mas ordenado y se cumple con el paradigma.

Vamos entonces a iniciar una aplicación base.

from flask import Flask
from controllers import init_controllers

app = Flask(__name__, static_folder='static')
app.secret_key = 'holamundo'

init_controllers(app)

if __name__ == '__main__':
     app.run()

La aplicacion base que podemos ver, importa lo esencial de Flask, o sea los métodos pero además llamamos al directorio Controllers, donde estan dos archivos principales. init.py y controller.py

En el primero, es donde se registrarán, los controladores de la siguiente manera.

from flask import Blueprint
from .Controller import user.

def init_controllers(app):
    app.register_blueprint(user)

En la primera linea, importamos el método BluePrint, el cuál nos permite registrar los archivos individuales de los controladores. Cada controlador registrado será primero importado en la parte superior, siendo la función ìnit_controllers() la que registrará cada uno.

En el controlador irá algo así.

from flask import Blueprint
# esta variable inicializará Blueprint
user = Blueprint('usuario', __name__)

De aqui hacia abajo, crearemos los métodos de ruta y procesos.
@user.route('/usuario')
def get_usuarios:
    # Tu codigo
    pass

El modelo.

Un modelo en Python puede ser de dos maneras. Usándolo solo como conector a la base datos o usando un ORM (Object Relational Model), que permite crear y manipular la base de datos a nivel de código. Acá en el ejemplo, sin embargo, usaremos la antigua fórmula.

Para el ejemplo usaremos PostgreSQL, una base de datos relacional que en lo personal, me gusta mucho y su librería Python psycopg2

import psycopg2

"""
Creamos primero una conexion. Normalmente iría en un archivo aparte, pero para el ejemplo se realizará en el mismo Modelo.
"""
def DbConn(host, port, user, password):
    try:
        conexion = psycopg2.connect(
            host='localhost',
            database='baseprueba',
            user='usuariobasedatos',
            password='clavebasedatos'
        )
        return conexion
    except Exception as e:
        print(f"No se pudo conectar: {str(e)}")

# Funcion estandar para traer datos.
def get_usuarios():
    conn = DBConn()
    string = 'select * from public.usuarios;'

    try:
        sql = conn.cursor()
        sql.execute(string)
        data = sql.fetchall()
        sql.close()

        return data
    except psycopg2.DatabaseError as e:
        print(f'Ocurrio el siguiente error => {str(e)}')
    finally:
        conexion.close()

Para conectar el modelo con el controlador se hace la importación de la manera estándar, haciendo referencia al directorio donde se encuentra el archivo.

from models import usuarioModel

Una vez importado, dentro de la función agregamos lo siguiente. Quedaría así

from models import usuarioModel

user = Blueprint('usuario', __name__)

@user.route('/usuario')
def get_usuarios:
    # Llamamos al metodo dentro del archivo usuarioModel.
    usuarios = usuarioModel.get_usuarios()
    return render_template('index.html', usuarios=usuarios)

Lo que hace esta función es sencillo: tomar lo enviado por el Modelo y pasarlo a la vista que es lo que veremos a continuación.

La vista.

La vista es un template.html que es el que recibe la información a través de parámetros definidos por Jinja2, que es el motor de plantilla por defecto.

El motor lo que hace, es renderizar la vista, usando una base, aunque tambien se puede crear el html completo. El ejemplo que se muestra es usando dicha base.

{% extends 'core/base.html'}
{% block title %}Lista de Usuarios{% endblock %}

{% block main %}
<section class="section">
    <div class="row">
        <div class="col-md-12">
            <h5>Lista de Usuarios</h5>
                    <hr>
                    <div class="table-responsive">
                        <table class="table table-bordered table-striped datatable" id="lista-usuarios">
                            <thead>
                                <th scope="col">#</th>
                                <th scope="col">DNI</th>
                                <th scope="col">Nombre Completo</th>
                                <th scope="col">Nombre de Usuario</th>
                                <th scope="col">Correo</th>
                                <th scope="col">Perfil</th>
                                <th scope="col">Empresa</th>
                                <th scope="col">Fecha de Creacion</th>
                                <th scope="col">Ver Perfil</th>
                                <th scope="col">Editar</th>
                                <th scope="col">Quitar</th>
                            </thead>
                            <tbody>
                                {% for fila in usuarios  %}
                                    <tr>
                                        <td>{{ loop.index }}</td>
                                        <td>{{ fila[1] }}</td>
                                        <td>{{ fila[2] }}</td>
                                        <td>{{ fila[3] }}</td>
                                        <td>{{ fila[4] }}</td>
                                        <td>{{ fila[5] }}</td>
                                        <td>{{ fila[6] }}</td>
                                        <td>{{ fila[7] }}</td>
                                        <td class="text-center">
                                            <a href="{{ url_for('usuario.get_pagina_usuario', usuario=fila[8] ) }}" class="btn btn-success btn-sm ver"><i class="bi bi-eye"></i></a>
                                        </td>
                                        <td class="text-center"><button type="button" class="btn btn-primary btn-sm editar" data-id="{{ fila[8] }}"><i class="bi bi-pencil-fill"></i></button></td>
                                        {% if fila[9] == 1 %}
                                            <td class="text-center"><button type="button" class="btn btn-danger btn-sm borrar" data-id="{{ fila[8] }}"><i class="bi bi-trash"></i></button></td>
                                        {% else %}
                                            <td class="text-center"><button type="button" class="btn btn-light btn-sm borrar" data-id="{{ fila[8] }}" disabled><i class="bi bi-dash-circle"></i></button></td>    
                                        {% endif %}
                                    </tr>
                                {% endfor %}
                            </tbody>
                        </table>
                    </div>
        </div>
    </div>
</section>
{% endblock %}
{% block scripts}{% endblock %}

La plantilla html que vemos a continuación, toma lo enviado por el controlador y utilizando la notación de Jinja2, va renderizando la data que el controlador pide al modelo.

Ventajas del MVC.

La primera gran ventaja de este paradigma es el mantenimiento. Al tener ordenado y definidas las entidades y procesos que intervienen, es más fácil depurar y encontrar los errores, para así subsanarlos, sean de datos, lógica o presentación.

Otra gran ventaja es que toda tecnología actual, lo utiliza en su mayoría, por lo que teniendo la noción de como funciona, es más fácil aprender cualquier framework, sea en el lenguaje que sea, además de las múltiples herramientas, sean librerías front o de manejo de datos, ayudan a un desarrollo más rápido y eficiente de cualquier aplicación.

Ventajas de Flask.

Si bien existen frameworks mucho más poderosos, como Django, Flask es más "flexible" , ya que solo incluye lo necesario para comenzar, pudiendo agregar mas librerías Python según tus necesidades, lo que ayuda a que el código resultante no sea tan pesado. Sin embargo, en cierto punto requiere más trabajo, con algunas cosas como validaciones etc., pero en lo personal, siento que tampoco es tanto.

Instalar Flask.

Instalar Flask es muy sencillo. Se dejaran los pasos tanto para Linux como para Windows.

En el caso de windows, se usa la librería chocolatey, la cual es un gestor de paquetes independiente. Se encuentra en https://chocolatey.org

1. Instalar Python.

#Linux
apt install python3 python3-dev python3-setuptools  -y 
#Windows con chocolatey
choco install python3 -y

2. Instalar y crear entorno virtual.

La razón de crear estos entornes virtuales con virtualenv es para separar cada proyecto y sus librerías de la raíz de Windows. Asi se administran mejor, en caso de querer hacer otras cosas con el lenguaje.

En ambos casos -Windows y Linux- se usa el gestor de paquetes del lenguaje, llamado pip

#Instalar virtualenv
pip install virtualenv

3. Crear el entorno virtual.

Se puede crear en cualquier parte del sistema. Al crear el directorio donde tendrás tu proyecto, En la consola de tu SO, realiza esto.

#Linux
virtualenv venv

#Windows
python -m venv venv

Una vez ejecutado, creara directorios donde se descargaran las librerías necesarias. En este caso, usaremos las que se describen en el artículo (Flask, psycopg2 y otras). El siguiente paso, es activar la instancia.

# Linux
source venv/bin/activate
# Windows
\venv\Scripts\activate

Una vez activo, todo lo que instalemos con pip, solo será utilizado dentro del entorno virtual. Procedemos a instalar lo que necesitamos.

# Instalar el framework
pip install Flask
# Instalar el motor de plantillas
pip install Jinja2
#Instalar motor de base de datos. En linux y windows es diferente
pip install psycopg2
# En linux
pip install psycopg2-binary

Y sería todo. Luego se procede a crear los archivos y directorios necesarios descritos mas arriba.

4. Guardar e instalar librerías desde archivo de texto.

A medida que crece nuestro proyecto, iremos implementando mas librerías, por lo que es necesario irlas guardando en un archivo de texto. Esto se hace de la siguiente manera.

pip freeze > requirements.txt

Esto guardará todas las librerías en el archivo de la siguiente manera.

Flask=3.0.0
psycopg=2.9
Jinja2= 2.0

Para reinstalarlas, solo ejecutas el siguiente comando.

pip install -r requirements.txt

Conclusión.

Si quieres iniciarte en el mundo del desarrollo web en Python, puedes optar por Flask como tu inicio. Es intuitivo y escalable, permitiendo una mejor eficiencia, tanto en recursos como en tiempo de desarrollo.

Ciertamente frameworks como Django tienen muchas herramientas que facilitan el desarrollo, después de todo, la idea es agilizar el tiempo en los proyectos, pero Flask, aun teniendo solo lo esencial para empezar, permite mantener el punto medio, entre la agilidad de programar lo que necesitas y el control de tu código.

Sobre el Modelo-Vista-Controlador, hay otros paradigmas como el funcional, Singleton, etc, pero sigue siendo el estándar de la industria, por su facilidad de uso y comprensión, lo que permite que tus proyectos de desarrollo, sean mas ágiles y eficientes.

0
Subscribe to my newsletter

Read articles from Hermann Pollack (hpollack95) directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Hermann Pollack (hpollack95)
Hermann Pollack (hpollack95)