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

Einstellungen der Flask-Anwendung, die von einem Administrator während des Betriebs geändert wurden.

Die Anwendungskonfiguration muss statisch sein, die Anwendungseinstellungen müssen dynamisch sein.

26 Juli 2019
In Flask
post main image
Original photo unsplash.com/@ssvveennn

In Flask haben wir das Konfigurationsobjekt, mit dem Datenbankparameter, E-Mail-Parameter usw. angegeben werden können. Wenn wir ein Flask-Programm ausführen, erstellt es zuerst die Anwendung. Sobald die Anwendung erstellt wurde, überspringen nachfolgende Anforderungen die Erstellung der Anwendung und werden zu den Blueprint-Ansichten umgeleitet.

Wenn Flask startet, werden die Konfigurationsvariablen geladen und verwendet. Wichtig zu verstehen ist, dass jeder Besucher seine eigene Instanz erhält. Sobald die Flask-Anwendung läuft, können wir die Konfigurationsvariablen ändern, aber was nützt das? Wenn wir eine Konfigurationsvariable in einer Instanz ändern, dann ist dies in anderen Instanzen nicht sichtbar.

Ich glaube auch, dass wir zwischen Konfigurationsvariablen wie Datenbank, E-Mail, Sitzungs-Setup-Variablen und Einstellungsvariablen unterscheiden sollten, die wir spontan ändern wollen, wie der Text des Programmnamens, der in Vorlagen angezeigt wird, oder eine boolesche Zulassung/Blockregistrierung. Wir sollten in der Lage sein, die Einstellungsvariablen mit einem Administrator zu verwalten und andere laufende Instanzen dazu zu bringen, sie zu verwenden, ohne diese anderen Instanzen neu zu laden.

Kurz gesagt, um Anwendungseinstellungen zu implementieren, müssen wir Folgendes tun:

  • Definition der Klassen für Anwendungseinstellungen
  • Laden Sie die aktuelle Version der Anwendungseinstellungen, wenn die Flask-App erstellt wird.
  • Erstellen Sie eine Admin-Funktion, um die Anwendungseinstellungen zu bearbeiten und eine neue Version der Anwendungseinstellungen zu erstellen.
  • Erstellen Sie eine Admin-Funktion, um eine neue Version der Anwendungseinstellungen zu aktivieren.
  • Andere Instanzen veranlassen, eine neu aktivierte Version der Anwendungseinstellungen zu verwenden.
  • Machen Sie die Anwendungseinstellungen in unseren Jinja-Vorlagen zugänglich.

Definition der Anwendungseinstellungsklassen

Voraussetzung ist, dass es möglich sein muss, verschiedene Versionen der Anwendungseinstellungen zu erstellen. Dies ist mehr Arbeit, aber es ermöglicht den problemlosen Wechsel zu einer neuen Version und den Rückwechsel zu einer früheren Version. Ich verwende ein Klassenattribut/Datenbanktabellenfeld seqno, um eine Version zu identifizieren.

Die Anwendungseinstellungen, Einstellungen, sind in Abschnitte, SettingSections, gruppiert und haben einen Werttyp, der angibt, ob es sich um eine Ganzzahl, eine Zeichenkette oder einen Booleschen Wert handelt. Bei jedem Speichern der Anwendungseinstellungen wird eine neue Version der Anwendungseinstellungen erstellt. Diese Version kann besichtigt und wenn alles in Ordnung ist, kann sie aktiviert werden. Ich habe auch eine from_seqno-Variable hinzugefügt, die die Version angibt, die wir geändert haben, ich verwende diese, um die Änderungen zwischen den Versionen anzuzeigen.

Schließlich gibt es noch die Anwendungseinstellungen seqno oder Version, SettingSeqno, die die Versionsnummer der aktiven Version der Anwendungseinstellungen enthält. Beachten Sie, dass ich keine Backpopulationen von Slideshows ausgelassen habe, ich glaube nicht, dass es etwas hinzufügt, siehe auch einen früheren Beitrag.

class SettingSeqno(Base):

    __tablename__ = 'setting_seqno'

    id = Column(Integer, primary_key=True)
    ...
    # only one can be active at a time
    active_seqno = Column(Integer, server_default='0', index=True)


class Setting(Base):

    __tablename__ = 'setting'

    id = Column(Integer, primary_key=True)
    ...
    # seqno settings is the group of settings at a certain moment
    seqno = Column(Integer, server_default='0', index=True)
    name = Column(String(60), server_default='')
    # from_seqno is the seqno that was the base of this seqno
    from_seqno = Column(Integer, server_default='0', index=True)
    value = Column(String(60), server_default='')
    value_type = Column(Integer, server_default='0')
    setting_section_id = Column(Integer, ForeignKey('setting_section.id'))


class SettingSection(Base):

    __tablename__ = 'setting_section'

    id = Column(Integer, primary_key=True)
    ...
    # seqno settings is the group of settings at a certain moment
    seqno = Column(Integer, server_default='0', index=True)
    name = Column(String(60), server_default='')
    # from_seqno is the seqno that was the base of this seqno
    from_seqno = Column(Integer, server_default='0', index=True)

Laden Sie die aktuelle Version der Anwendungseinstellungen, wenn die Flask-App erstellt wird.

Ich habe dies getan, indem ich ein AppSettings-Objekt erstellt habe, ein bisschen wie beim Erstellen einer Flask-Erweiterung. In der Funktion __init__ werden die Anwendungseinstellungen aus der Datenbank geladen. In der Funktion create_app habe ich gerade die Zeile hinzugefügt:

app.app_settings = AppSettings(app)

Beachten Sie, dass ich app_settings mit 'app.' voranstelle, um app_settings global zu machen. In der Funktion create_app kann ich sie als app.app_settings und in den Blueprint-Funktionen als current_app.app_settings bezeichnen. So weit so gut, dass wir jetzt Anwendungseinstellungen haben, die wir in unserer Anwendung verwenden können, z.B. durch Aufruf:

allow_registration = current_app.app_settings.get_value('SECTION_AUTH', 'ALLOW_REGISTRATION')

Erstellen Sie eine Admin-Funktion, um die Anwendungseinstellungen zu bearbeiten und eine neue Version der Anwendungseinstellungen zu erstellen.

Hier geht es um das Design von Templates und Coding. Ich habe eine Listenseite, die eine Liste aller Versionen enthält, und eine Bearbeitungsseite, die zum Bearbeiten der Anwendungseinstellungen verwendet wird. Jedes Mal, wenn Änderungen gespeichert werden, werden sie in einer neuen Version der Anwendungseinstellungen gespeichert. Diese neue Version wird nicht automatisch aktiviert. Die Seite mit den Versionen zeigt auch die Unterschiede zwischen den Einstellungen der Anwendungseinstellungen mit Pythons difflib.

Erstellen Sie eine Admin-Funktion, um eine neue Version der Anwendungseinstellungen zu aktivieren.

Die Listenseite mit den Versionen hat auch eine Auswahlknopfgruppe mit einem Auswahlknopf für jede Version, die aktivierte hat den Auswahlknopf markiert. Um zu einer neuen Version zu wechseln, wählen Sie einfach die Version aus und aktualisieren Sie im Code den Wert von SettingSeqno.active_seqno und laden Sie die Versionen der Anwendungseinstellungen erneut aus der Datenbank. Das funktioniert gut, aber nur im Falle des Admin, die anderen Instanzen (Website-Besucher) sind sich dessen nicht bewusst.

Andere Instanzen veranlassen, eine neu aktivierte Version der Anwendungseinstellungen zu verwenden.

Da wir die Flask-Anwendung für Website-Besucher nicht neu laden wollen, müssen wir nach einem anderen Weg suchen. Was ich getan habe, ist, den Flask before_request Handler zu verwenden. Ich benutze eine Session-Variable'app_settings_current_seqno' und den Datenbankwert'active_seqno', um zu prüfen, ob eine neue Version der Anwendungseinstellungen geladen werden muss.

Leider müssen wir eine Datenbankanforderung in Flasks before_request Handler hinzufügen, um die aktuelle Version der Anwendungseinstellungen zu erhalten. Dies könnte durch eine gemeinsame Datei usw. vermieden werden, aber da ich in Zukunft auch einige andere Werte hinzufügen möchte, habe ich mich entschieden, ein zusätzliches Objekt/Tabelle BeforeRequestData hinzuzufügen, das eine Kopie der Variablen active_seqno enthält. Um es kurz zu machen: Wenn die Sitzungsvariable vom Datenbankwert abweicht, werden die Anwendungseinstellungen aus der Datenbank neu geladen. Danach wird die Sitzungsvariable auf den Wert active_seqno aktualisiert, was verhindert, dass dies bei nachfolgenden Anfragen geschieht.

    @app.before_request
    def before_request():
        with app.app_context():
            ...
            # reload application settings if session var not equal to database var
            if session_app_settings_current_seqno != database_app_settings_current_seqno:
                app.app_settings.load_from_database(app)
                session['app_settings_current_seqno'] = database_app_settings_current_seqno

Machen Sie die Anwendungseinstellungen in unseren Jinja-Vorlagen zugänglich.

Fast geschafft. Flask-Konfigurationsvariablen werden standardmäßig von flask übergeben, so dass Sie auf die Konfigurationsvariablen in Vorlagen zugreifen können. Um unsere Anwendungseinstellungen an die Vorlagen zu übergeben, verwenden wir einen Kontextprozessor. Ich habe bereits einen Kontextprozessor, der Dinge injiziert, also habe ich einfach die Anwendungseinstellungen hinzugefügt.

Ich habe auch die aktuelle Version der Anwendungseinstellungen hinzugefügt, so dass ich auf der Webseite leicht erkennen konnte, welche Version der Anwendungseinstellungen verwendet wird:

    @app.context_processor
    def inject_base_template_parameters():

        base_template_parameters = {}

        # app_settings
        base_template_parameters['app_settings'] = app.app_settings.get_setting_section_name2setting_name2settings()

        # app_settings seqno
        app_settings_current_seqno = ''
        if session.get('app_settings_current_seqno'):
            app_settings_current_seqno = str( session.get('app_settings_current_seqno') )
        base_template_parameters['app_settings_current_seqno'] = app_settings_current_seqno
        ...
        return base_template_parameters

Und in der Basisschablone:

	<p class="copyright text-muted small">
		{{ app_settings['SECTION_GENERAL']['WEBSITE_COPYRIGHT']['value'] }} [{{ app_settings_current_seqno }}] [72ms]
	</p>

Zusammenfassung

Es war keine leichte Aufgabe, dies umzusetzen, aber es gab mehr Verständnis für Flask. Das Erstellen einer Flask-App unterscheidet sich von der Ausführung nachfolgender Anfragen. Es ist verwirrend, dass wir bei der Initialisierung das Flask-App-Objekt und danach das Flask current_app-Objekt verwenden müssen. Ich habe darüber irgendwo gelesen, werde darüber immer wieder lesen müssen, und immer wieder, und immer wieder.

Links / Impressum

Configuration Handling
https://flask.palletsprojects.com/en/1.1.x/config/

Context Processors
https://flask.palletsprojects.com/en/1.1.x/templating/#context-processors

Dynaconf - Easy and Powerful Settings Configuration for Python
https://dynaconf.readthedocs.io/en/latest/index.html

How to reload a configuration file on each request for Flask?
https://stackoverflow.com/questions/39456672/how-to-reload-a-configuration-file-on-each-request-for-flask

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.