angle-up arrow-clockwise arrow-counterclockwise arrow-down-up arrow-left at calendar card-list chat check envelope folder house info-circle pencil people person person-plus phone plus question-circle search tag trash x

Gemeinsame Nutzung von Modellen, Klassen, Blueprints und Vorlagen zwischen Anwendungen mit Flask DispatcherMiddleWare

12 Mai 2020 durch Peter

Durch die Vermeidung von Doppelarbeit wird Ihr Code kleiner und besser wartbar.

post main image
https://unsplash.com/@michel_catalisano

Diese Website läuft unter Flask. Sie verwendet DispatcherMiddleWare zur Ausführung der Frontend-App und der Admin-App. Die Dokumente Flask besagen, dass die Anwendungen Flask in diesem Fall vollständig voneinander isoliert sind. Das ist wahr, aber oft gibt es eine Menge Code, den wir zwischen diesen Anwendungen austauschen möchten.

Dinge, die wir teilen wollen

Beide Anwendungen verwenden die gleiche Datenbank, was bedeutet, dass wir die Datei models.py gemeinsam nutzen wollen. Dann haben wir bestimmte Klassen, die wir selbst geschrieben haben. Ich habe zum Beispiel Klassen wie MailMessage und FormValidation geschrieben. Sie sollten von beiden Apps verwendet werden.

Ich verwende auch Blueprints , das gemeinsam genutzt werden sollte, zum Beispiel das 'auth' Blueprint , das die Authentifizierungsfunktionen wie Anmelden, Konto erstellen, Passwort zurücksetzen behandelt. Die von diesen Blueprints verwendeten Vorlagen sollten ebenfalls gemeinsam genutzt werden. Es gibt auch andere Vorlagen, die gemeinsam genutzt werden sollten, wie z.B. Makros, um Formulare auf eine Seite zu stellen, Makros, die Schaltflächen in Tabellen einfügen.

Hinzufügen eines gemeinsamen Verzeichnisses

In einem früheren Beitrag habe ich über die Verwendung von DispatcherMiddleware geschrieben und eine grundlegende Verzeichnisstruktur vorgestellt. Jetzt ist es an der Zeit, ein gemeinsames Verzeichnis hinzuzufügen, siehe unten.

|
|-- 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

Änderungen am statischen Ordner

Ich habe bereits eine Umgebungsvariable, die das statische Verzeichnis enthält. Der Grund dafür ist, dass sich das statische Verzeichnis an einem anderen Ort auf dem Produktionssystem befindet. In der Anwendung create_app() von sowohl app_frontend als auch app_admin erstellen wir die Anwendung Flask mit dem gleichen statischen Verzeichnis:

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

Änderungen an Importen

Natürlich müssen wir Änderungen an den anfänglichen Importen vornehmen. Zum Beispiel ändern wir in den Dateien app_frontend Python die Importe der Dateien Python aus app_frontend :

    # register  blueprints

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

zu:

    # register  blueprints

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

Änderungen an template_folders

Das ist ein bisschen magisch. Ich habe beim Erstellen der Anwendung Flask keinen template_folder angegeben, was bedeutet, dass Flask den Standardordner 'templates' verwendet. Aber wie können wir auf die gemeinsamen Vorlagen zugreifen? Glücklicherweise können wir ein 'Vorlagen'-Verzeichnis angeben, wenn wir eine Blueprint-Anwendung erstellen. Wenn Sie angeben:

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

dann teilen Sie Flask mit, dass es ein Verzeichnis 'templates' im Verzeichnis Blueprint 'auth' gibt. Dieses Verzeichnis ist relativ (!) zum Blueprint 'auth'-Verzeichnis. Die Verzeichnisstruktur sollte dann wie folgt aussehen:

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

Beachten Sie, dass es ein zusätzliches Verzeichnis 'auth' im Vorlagenverzeichnis gibt, da wir die Datei views.py nicht ändern wollen. Diese Datei enthält Ansichtsfunktionen, die mit enden:

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

Wenn wir so vorgehen würden, bekämen wir ein Vorlagenverzeichnis für jedes freigegebene Blueprint. nicht wirklich das, was wir wollen. Das gemeinsame Vorlagenverzeichnis muss die gleiche Struktur wie die Vorlagenverzeichnisse app_frontend und app_admin haben, ein einziges Verzeichnis mit Unterverzeichnissen für jedes Blueprint. Um dies zu erreichen, ändern wir die Blueprint template_folder so, dass sie auf shared/templates zeigt:

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

Wir tun dies für alle gemeinsamen Blueprints und wir sind fertig. Das Magische daran ist, dass Sie dies nur für ein einziges gemeinsames Blueprint tun müssen. Es sieht so aus, als ob Flask eine Liste von Vorlagen-Suchverzeichnissen aufbaut, und sobald wir template_folder für das 'auth' Blueprint bearbeitet haben, wird der Pfad zu dieser Liste hinzugefügt, und die anderen gemeinsam genutzten Blueprints finden ebenfalls ihre Vorlagen. Aus der Dokumentation Flask : "Der Vorlagenordner (Blueprint) wird dem Suchpfad der Vorlagen hinzugefügt, jedoch mit einer niedrigeren Priorität als der Vorlagenordner der eigentlichen Anwendung.
Dies funktioniert, weil wir uns in diesem Fall auf ein einzelnes gemeinsames Vorlagenverzeichnis beziehen, aber ich würde es vorziehen, eine Vorlagen-Suchpfadliste auf Anwendungsebene angeben zu können. Es gibt Informationen, wie Sie dies tun können, siehe Links unten.

Übersetzungen

Wenn Sie eine mehrsprachige Website haben und Babel verwenden, müssen Sie sicherstellen, dass die Übersetzungen von app_frontend nicht nur aus dem Verzeichnis app_frontend , sondern auch aus dem gemeinsamen Verzeichnis generiert werden. Dasselbe gilt für app_admin. Um dies zu erreichen, fügen wir das Verzeichnis in die Datei babel_app_frontend.cfg ein:

[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

Zusammenfassung

Die gemeinsame Nutzung von Dateien zwischen Flask DispatcherMiddleWare-Apps macht Ihre Arbeit wesentlich einfacher, keine Duplikate. Ich hatte ein wenig Mühe mit den freigegebenen Vorlagen. Sie müssen sich wirklich etwas Zeit nehmen, um das zu verstehen. Am Ende habe ich einen Test erstellt und den Ablauf im Code Jinja verfolgt.

Das Freigeben von Dateien erschien nicht so schwierig, es beginnt mit einer soliden Verzeichnisstruktur. Dies beweist erneut die Fähigkeiten von Flask. Kein Hacken notwendig, es ist bereits alles vorhanden.

Links / Impressum

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

Einen Kommentar hinterlassen

Kommentieren Sie anonym oder melden Sie sich zum Kommentieren an.

Kommentare

Eine Antwort hinterlassen

Antworten Sie anonym oder melden Sie sich an, um zu antworten.