angle-uparrow-clockwisearrow-counterclockwisearrow-down-uparrow-leftatcalendarcard-listchatcheckenvelopefolderhouseinfo-circlepencilpeoplepersonperson-fillperson-plusphoneplusquestion-circlesearchtagtrashx

Compartiendo modelos, clases, Blueprints y plantillas entre aplicaciones con Flask DispatcherMiddleWare

Al evitar la duplicación, su código se hace más pequeño y más fácil de mantener.

12 mayo 2020
post main image
https://unsplash.com/@michel_catalisano

Este sitio está corriendo Flask. Utiliza DispatcherMiddleWare para ejecutar la aplicación de frontend y la aplicación de administración. Los documentos Flask establecen que las aplicaciones Flask en este caso están completamente aisladas unas de otras. Eso es cierto, pero a menudo hay mucho código que queremos compartir entre estas aplicaciones.

Cosas que queremos compartir

Ambas aplicaciones usan la misma base de datos, lo que significa que queremos compartir el archivo models.py. Entonces tenemos ciertas clases que escribimos nosotros mismos. Por ejemplo, yo escribí clases como MailMessage y FormValidation. Deberían ser usadas por ambas aplicaciones.

También estoy usando Blueprints que debe ser compartido, por ejemplo el 'auth' Blueprint que maneja las funciones de autenticación como iniciar sesión, crear cuenta, restablecer contraseña. Las plantillas usadas por estos Blueprints también deben ser compartidas. También hay otras plantillas que deberían ser compartidas, como macros para poner formularios en una página, macros que ponen botones en tablas.

Añadir un directorio compartido

En un post anterior escribí sobre el uso de DispatcherMiddleware y presenté una estructura básica de directorios. Ahora es el momento de agregar un directorio compartido, ver abajo.

|
|-- project
|   |-- alembic
|   |   `-- 
|   |   
|   |--  app_admin
|   |   |-- __init__.py
|   |   |--  blueprints
|   |   |   |-- content_item
|   |   |   |   |-- forms.py
|   |   |   |   |-- __init__.py
|   |   |   |   `--  views.py
|   |   |   |--  user
|   |   |   |   |-- forms.py
|   |   |   |   |-- __init__.py
|   |   |   |   `--  views.py
|   |   |-- templates
|   |   |   |-- content_item
|   |   |   |   |-- content_items_list.html
|   |   |   |   `-- 
|   |   |   |--  user
|   |   |   |   |--  users_list.html
|   |   |   |   `-- 
|   |   |   |-- base.html
|   |   `-- translations
|   |       `-- es_ES
|   |           `-- LC_MESSAGES
|   |               |-- messages.mo
|   |               `--  messages.po
|   |   
|   |--  app_frontend
|   |   |-- __init__.py
|   |   |--  blueprints
|   |   |   |-- comments
|   |   |   |   |-- forms.py
|   |   |   |   |-- __init__.py
|   |   |   |   `--  views.py
|   |   |   `-- demo_crud_view_uuid
|   |   |       |-- forms.py
|   |   |       |-- __init__.py
|   |   |       `--  views.py
|   |   |-- templates
|   |   |   |-- comments
|   |   |   |   |-- comment_form.html
|   |   |   |   `-- 
|   |   |   `-- base.html
|   |   `-- translations
|   |       `-- es_ES
|   |           `-- LC_MESSAGES
|   |               |-- messages.mo
|   |               `--  messages.po
|   |   
|   |-- shared
|   |   |--  blueprints
|   |   |   |-- account
|   |   |   |   |-- forms.py
|   |   |   |   |-- __init__.py
|   |   |   |   `--  views.py
|   |   |   `-- auth
|   |   |       |-- forms.py
|   |   |       |-- __init__.py
|   |   |       `--  views.py
|   |   |-- static
|   |   |   |-- blog
|   |   |   |-- css
|   |   |   |-- js
|   |   |   |-- vendor
|   |   |   `-- robots.txt
|   |   |-- templates
|   |   |   |-- account
|   |   |   |   `-- overview.html
|   |   |   |-- auth
|   |   |   |   `-- login.html
|   |   |   |-- macros
|   |   |   |   `-- 
|   |   |   `-- boxed.html
|   |   |
|   |   |-- constants.py
|   |   |-- class_app_mail.py
|   |   |-- class_input_validation.py

Los cambios en la carpeta estática

Ya tengo una variable de entorno que contiene el directorio estático. La razón es que el directorio estático está en un lugar diferente del sistema de producción. En el create_app() tanto del app_frontend como del app_admin creamos la aplicación Flask con la misma carpeta estática:

    flask_static_folder = os.getenv('FLASK_STATIC_FOLDER')
    app =  Flask(
        __name__, 
        static_folder=flask_static_folder,
    )

Los cambios en las importaciones

Por supuesto que debemos hacer cambios en las importaciones iniciales. Por ejemplo, en los archivos app_frontend Python cambiamos las importaciones de los archivos Python desde:

    # register  blueprints

    # authentication (shared)
    from .blueprints.auth.views  import auth_blueprint
    app.register_blueprint(auth_blueprint, url_prefix='/<lang_code>/auth')

a:

    # register  blueprints

    # authentication (shared)
    from shared.blueprints.auth.views  import auth_blueprint
    app.register_blueprint(auth_blueprint, url_prefix='/<lang_code>/auth')

Cambios en template_folders

Esto es un poco mágico. No especifiqué un template_folder al crear la aplicación Flask , lo que significa que Flask utiliza la carpeta "plantillas" por defecto. ¿Pero cómo podemos acceder a las plantillas compartidas? Afortunadamente podemos especificar un directorio de 'plantillas' cuando creamos un Blueprint. Si especificas:

auth_blueprint  =  Blueprint('auth', __name__,  template_folder='templates')

entonces le dices a Flask que hay un directorio 'templates' en el directorio 'auth' de Blueprint . Este directorio es relativo (!) al directorio 'auth' de Blueprint . La estructura del directorio entonces debería ser como esta:

|   |-- shared
|   |   |--  blueprints
|   |   |   `-- auth
|   |   |       |-- forms.py
|   |   |       |-- __init__.py
|   |   |       |--  views.py
|   |   |       `-- templates
|   |   |           `-- auth
|   |   |               |-- login.html
|   |   |               `-- 

Tengan en cuenta que hay un directorio adicional 'auth' en el directorio de plantillas porque no queremos cambiar el archivo views.py. Este archivo contiene las funciones de visualización que terminan en:

    ...
    return  render_template(
        'auth/login.html',
        ...

Si procedemos de esta manera obtenemos un directorio de plantillas para cada Blueprint compartido. no es realmente lo que queremos. El directorio de plantillas compartido debe tener la misma estructura que los directorios de plantillas app_frontend y app_admin , un único directorio con subdirectorios para cada Blueprint. Para lograr esto, cambiamos el Blueprint template_folder para que apunte a shared/templates:

auth_blueprint  =  Blueprint('auth', __name__,  template_folder='../../templates')

Hacemos esto para todos los Blueprints compartidos y hemos terminado. Lo que es mágico de esto es que sólo tienes que hacer esto para un solo Blueprint compartido. Parece que Flask está construyendo una lista de directorios de búsqueda de plantillas y una vez que el template_folder para el 'auth' Blueprint ha sido procesado, la ruta se añade a esta lista y los otros Blueprints compartidos también encuentran sus plantillas. De la documentación de Flask : 'La carpeta de plantillas (Blueprint) se agrega a la ruta de búsqueda de plantillas pero con una prioridad menor que la carpeta de plantillas de la aplicación real'.
Esto funciona porque en este caso nos referimos a un único directorio de plantillas compartido, pero preferiría poder especificar una lista de ruta de búsqueda de plantillas a nivel de aplicación. Hay información disponible sobre cómo puede hacerlo, véase los enlaces que figuran a continuación.

Traducciones

Cuando se tiene un sitio multilingüe y se utiliza Babel se debe asegurar que las traducciones de app_frontend no sólo se generan desde el directorio app_frontend sino también desde el directorio compartido. Lo mismo se aplica a app_admin. Para lograr esto, añadimos el directorio al archivo babel_app_frontend.cfg:

[python:  app_frontend/**.py]
[python: shared/**.py]
[jinja2:  app_frontend/templates/**.html]
[jinja2:  shared/templates/**.html]
extensions=jinja2.ext.autoescape,jinja2.ext.with_
encoding = utf-8

Resumen

Compartir archivos entre las aplicaciones Flask DispatcherMiddleWare hace tu trabajo mucho más fácil, sin duplicados. Tuve un poco de dificultad con las plantillas compartidas. Realmente debes tomarte un tiempo para entender esto. Al final creé una prueba y seguí el flujo en el código Jinja .

Compartir archivos no parecía tan difícil, empieza con una sólida estructura de directorios. Una vez más esto demuestra las capacidades de Flask. No es necesario hackear, ya está todo ahí.

Enlaces / créditos

Application Dispatching
https://flask.palletsprojects.com/en/1.1.x/patterns/appdispatch/

flask blueprint template folder
https://stackoverflow.com/questions/7974771/flask-blueprint-template-folder

Modular Applications with Blueprints
https://flask.palletsprojects.com/en/1.1.x/blueprints/#modular-applications-with-blueprints

Two Flask apps, frontend and admin, on one domain using DispatcherMiddleware
http://127.0.0.1:8000/en/blog/two-flask-apps-frontend-and-admin-on-one-domain-using-dispatchermiddleware

Deje un comentario

Comente de forma anónima o inicie sesión para comentar.

Comentarios

Deje una respuesta.

Responda de forma anónima o inicie sesión para responder.