Kapitel 4. Webformulare

Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com

Die Templates, mit denen du in Kapitel 3 gearbeitet hast, sind unidirektional, d. h., sie ermöglichen den Informationsfluss vom Server zum Benutzer. Bei den meisten Anwendungen müssen die Informationen jedoch auch in die andere Richtung fließen, d. h. der Nutzer liefert Daten, die der Server annimmt und verarbeitet.

Mit HTML ist es möglich, Webformulare zu erstellen, in die die Benutzer Informationen eingeben können. Die Formulardaten werden dann vom Webbrowser an den Server übermittelt, normalerweise in Form einer POST Anfrage. Das in Kapitel 2 vorgestellte Flask-Anfrageobjekt stellt alle vom Client in einer Anfrage gesendeten Informationen zur Verfügung und ermöglicht insbesondere bei POST Anfragen, die Formulardaten enthalten, den Zugriff auf die Benutzerinformationen über request.form.

Obwohl die Unterstützung durch das Request-Objekt von Flask für die Bearbeitung von Webformularen ausreichend ist, gibt es eine Reihe von Aufgaben, die mühsam und repetitiv werden können. Zwei gute Beispiele sind die Erstellung von HTML-Code für die Formulare und die Validierung der übermittelten Formulardaten.

Die Flask-WTF-Erweiterung macht die Arbeit mit Webformularen viel angenehmer. Diese Erweiterung ist ein Flask-Integrations-Wrapper um das Framework-agnostische WTForms-Paket.

Flask-WTF und seine Abhängigkeiten können mit pip installiert werden:

(venv) $ pip install flask-wtf

Konfiguration

Im Gegensatz zu den meisten anderen Erweiterungen muss Flask-WTF nicht auf der Anwendungsebene initialisiert werden, sondern erwartet, dass die Anwendung einen geheimen Schlüssel konfiguriert hat. Ein geheimer Schlüssel ist eine Zeichenkette mit beliebigem und eindeutigem Inhalt, die als Verschlüsselungs- oder Signierschlüssel verwendet wird, um die Sicherheit der Anwendung auf verschiedene Weise zu verbessern. Flask verwendet diesen Schlüssel, um den Inhalt der Benutzersitzung vor Manipulationen zu schützen. Du solltest für jede Anwendung, die du erstellst, einen anderen geheimen Schlüssel wählen und dafür sorgen, dass diese Zeichenfolge niemandem bekannt ist. Beispiel 4-1 zeigt, wie du einen geheimen Schlüssel in einer Flask-Anwendung konfigurierst.

Beispiel 4-1. hello.py: Flask-WTF Konfiguration
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'

Das app.config Wörterbuch ist ein allgemeiner Ort, um Konfigurationsvariablen zu speichern, die von Flask, Erweiterungen oder der Anwendung selbst verwendet werden. Konfigurationswerte können dem app.config Objekt mit der Standard-Wörterbuchsyntax hinzugefügt werden. Das Konfigurationsobjekt verfügt auch über Methoden, um Konfigurationswerte aus Dateien oder der Umgebung zu importieren. Eine praktischere Möglichkeit, Konfigurationswerte für eine größere Anwendung zu verwalten, wird in Kapitel 7 behandelt.

Für Flask-WTF muss ein geheimer Schlüssel in der Anwendung konfiguriert werden, denn dieser Schlüssel ist Teil des Mechanismus, mit dem die Erweiterung alle Formulare vor Cross-Site-Request-Forgery (CSRF)-Angriffen schützt. Ein CSRF-Angriff erfolgt, wenn eine böswillige Website Anfragen an den Anwendungsserver sendet, auf dem der Benutzer gerade angemeldet ist. Flask-WTF erzeugt Sicherheits-Tokens für alle Formulare und speichert sie in der Benutzersitzung, die mit einer kryptografischen Signatur geschützt ist, die aus dem geheimen Schlüssel generiert wird.

Hinweis

Um die Sicherheit zu erhöhen, sollte der geheime Schlüssel in einer Umgebungsvariablen gespeichert werden, anstatt ihn in den Quellcode einzubauen. Diese Technik wird in Kapitel 7 beschrieben.

Klassen bilden

Bei der Verwendung von Flask-WTF wird jedes Webformular auf dem Server durch eine Klasse repräsentiert, die von der Klasse FlaskForm erbt. Die Klasse definiert die Liste der Felder des Formulars, die jeweils durch ein Objekt dargestellt werden. Jedes Feldobjekt kann mit einem oder mehreren Validatoren versehen werden. Ein Validator ist eine Funktion, die überprüft, ob die vom Benutzer eingegebenen Daten gültig sind.

Beispiel 4-2 zeigt ein einfaches Webformular mit einem Textfeld und einem Submit-Button.

Beispiel 4-2. hello.py: Definition der Formularklasse
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import DataRequired

class NameForm(FlaskForm):
    name = StringField('What is your name?', validators=[DataRequired()])
    submit = SubmitField('Submit')

Die Felder im Formular sind als Klassenvariablen definiert, und jeder Klassenvariablen ist ein Objekt zugewiesen, das mit dem Feldtyp verknüpft ist. In diesem Beispiel hat das Formular NameForm ein Textfeld mit dem Namen name und einen Submit-Button mit dem Namen submit. Die Klasse StringField repräsentiert ein HTML <input> Element mit einem type="text" Attribut. Die Klasse SubmitField steht für ein HTML-Element <input> mit einem type="submit" -Attribut. Das erste Argument der Feldkonstruktoren ist die Beschriftung, die beim Rendern des Formulars in HTML verwendet werden soll.

Das optionale Argument validators im StringField Konstruktor definiert eine Liste von Prüfern, die auf die vom Benutzer übermittelten Daten angewendet werden, bevor sie akzeptiert werden. Der DataRequired() Validator stellt sicher, dass das Feld nicht leer übermittelt wird.

Hinweis

Die Basisklasse FlaskForm wird von der Flask-WTF-Erweiterung definiert und daher von flask_wtf importiert. Die Felder und Validatoren werden jedoch direkt aus dem WTForms-Paket importiert.

Die Liste der Standard-HTML-Felder, die von WTForms unterstützt werden, findest du in Tabelle 4-1.

Tabelle 4-1. WTForms Standard-HTML-Felder
Feldtyp Beschreibung

BooleanField

Kontrollkästchen mit den Werten True und False

DateField

Textfeld, das einen datetime.date Wert in einem bestimmten Format annimmt

DateTimeField

Textfeld, das einen datetime.datetime Wert in einem bestimmten Format annimmt

DecimalField

Textfeld, das einen decimal.Decimal Wert akzeptiert

FileField

Datei-Upload-Feld

HiddenField

Verstecktes Textfeld

MultipleFileField

Feld zum Hochladen mehrerer Dateien

FieldList

Liste der Felder eines bestimmten Typs

FloatField

Textfeld, das einen Gleitkommawert akzeptiert

FormField

Formular eingebettet als Feld in einem Containerformular

IntegerField

Textfeld, das einen ganzzahligen Wert annimmt

PasswordField

Passwort-Textfeld

RadioField

Liste der Optionsfelder

SelectField

Dropdown-Liste mit Auswahlmöglichkeiten

SelectMultipleField

Dropdown-Liste mit Mehrfachauswahl

SubmitField

Schaltfläche "Formular einreichen

StringField

Textfeld

TextAreaField

Mehrzeiliges Textfeld

Die Liste der in WTForms integrierten Validierer ist in Tabelle 4-2 aufgeführt.

Tabelle 4-2. WTForms Validatoren
Validator Beschreibung

DataRequired

Prüft, ob das Feld nach der Typkonvertierung Daten enthält

Email

Bestätigt eine E-Mail-Adresse

EqualTo

Vergleicht die Werte von zwei Feldern; nützlich, wenn ein Passwort zur Bestätigung zweimal eingegeben werden muss

InputRequired

Prüft, ob das Feld vor der Typkonvertierung Daten enthält

IPAddress

Überprüft eine IPv4-Netzwerkadresse

Length

Überprüft die Länge der eingegebenen Zeichenkette

MacAddress

Überprüft eine MAC-Adresse

NumberRange

Überprüft, ob der eingegebene Wert innerhalb eines numerischen Bereichs liegt

Optional

Erlaubt leere Eingaben in das Feld und überspringt zusätzliche Überprüfungen

Regexp

Überprüft die Eingabe anhand eines regulären Ausdrucks

URL

Überprüft eine URL

UUID

Überprüft eine UUID

AnyOf

Überprüft, ob die Eingabe einer von mehreren möglichen Werten ist

NoneOf

Überprüft, ob die Eingabe keiner der möglichen Werte ist

HTML-Rendering von Formularen

Formularfelder sind Callables, die, wenn sie von einer Vorlage aufgerufen werden, sich selbst in HTML umwandeln. Angenommen, die View-Funktion übergibt der Vorlage eine NameForm Instanz als Argument mit dem Namen form, dann kann die Vorlage ein einfaches HTML-Formular wie folgt erzeugen:

<form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name() }}
    {{ form.submit() }}
</form>

Beachte, dass das Formular zusätzlich zu den Feldern name und submit ein Element form.hidden_tag() enthält. Dieses Element definiert ein zusätzliches Formularfeld, das versteckt ist und von Flask-WTF verwendet wird, um CSRF-Schutz zu implementieren.

Natürlich ist das Ergebnis des Renderings eines Webformulars auf diese Weise extrem nackt. Alle Schlüsselwortargumente, die den Aufrufen zum Rendern der Felder hinzugefügt werden, werden in HTML-Attribute für das Feld umgewandelt. So kannst du dem Feld zum Beispiel die Attribute id oder class geben und dann CSS-Stile für sie definieren:

<form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name(id='my-text-field') }}
    {{ form.submit() }}
</form>

Aber selbst mit HTML-Attributen ist der Aufwand, der nötig ist, um ein Formular auf diese Weise darzustellen und es gut aussehen zu lassen, beträchtlich, daher ist es am besten, wenn du die Bootstrap-eigenen Formularstile verwendest, wann immer das möglich ist. Die Flask-Bootstrap-Erweiterung bietet eine High-Level-Hilfsfunktion, die ein komplettes Flask-WTF-Formular mit einem einzigen Aufruf mit den vordefinierten Formularstilen von Bootstrap rendert. Mit Flask-Bootstrap kann das vorherige Formular wie folgt gerendert werden:

{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}

Die Direktive import funktioniert genauso wie reguläre Python-Skripte und ermöglicht es, Template-Elemente zu importieren und in vielen Templates zu verwenden. Die importierte Datei bootstrap/wtf.html definiert Hilfsfunktionen, die Flask-WTF-Formulare mit Bootstrap darstellen. Die Funktion wtf.quick_form() nimmt ein Flask-WTF-Formularobjekt und rendert es mit den Standard-Bootstrap-Styles. Das vollständige Template für hello.py ist in Beispiel 4-3 zu sehen.

Beispiel 4-3. templates/index.html: Verwendung von Flask-WTF und Flask-Bootstrap zur Darstellung eines Formulars
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}

{% block title %}Flasky{% endblock %}

{% block page_content %}
<div class="page-header">
    <h1>Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!</h1>
</div>
{{ wtf.quick_form(form) }}
{% endblock %}

Der Inhaltsbereich der Vorlage hat jetzt zwei Abschnitte. Der erste Abschnitt ist ein Seitenkopf, der eine Begrüßung zeigt. Hier wird ein Template Conditional verwendet. Konditionale Bedingungen in Jinja2 haben das Format {% if condition %}...{% else %}...{% endif %}. Wenn die Bedingung den Wert True ergibt, wird das, was zwischen den Direktiven if und else steht, der gerenderten Vorlage hinzugefügt. Wenn die Bedingung False ergibt, wird stattdessen das, was zwischen else und endif steht, gerendert. Damit soll Hello, {{ name }}! wiedergegeben werden, wenn die Template-Variable name definiert ist, oder die Zeichenfolge Hello, Stranger!, wenn sie nicht definiert ist. Der zweite Abschnitt des Inhalts rendert die Form NameForm mit der Funktion wtf.quick_form().

Formularbehandlung in Ansichtsfunktionen

In der neuen Version von hello.py wird die Funktion index() view zwei Aufgaben haben. Zuerst rendert sie das Formular und dann empfängt sie die vom Benutzer eingegebenen Formulardaten. Beispiel 4-4 zeigt die aktualisierte Funktion index() view.

Beispiel 4-4. hello.py: ein Webformular mit GET- und POST-Methoden bearbeiten
@app.route('/', methods=['GET', 'POST'])
def index():
    name = None
    form = NameForm()
    if form.validate_on_submit():
        name = form.name.data
        form.name.data = ''
    return render_template('index.html', form=form, name=name)

Das Argument methods, das dem Dekorator app.route hinzugefügt wird, weist Flask an, die View-Funktion als Handler für GET und POST Anfragen in der URL-Map zu registrieren. Wenn methods nicht angegeben wird, wird die View-Funktion nur für die Bearbeitung von GET Anfragen registriert.

Die Aufnahme von POST in die Methodenliste ist notwendig, weil Formularübermittlungen viel bequemer als POST Anfragen behandelt werden. Es ist zwar möglich, ein Formular als GET Anfrage zu übermitteln, aber da GET Anfragen keinen Body haben, werden die Daten als Query-String an die URL angehängt und sind in der Adressleiste des Browsers sichtbar. Aus diesem und anderen Gründen werden Formularübertragungen fast immer als POST -Anfrage durchgeführt.

Die lokale Variable name wird verwendet, um den vom Formular erhaltenen Namen zu speichern, wenn er verfügbar ist; wenn der Name nicht bekannt ist, wird die Variable auf None initialisiert. Die View-Funktion erstellt eine Instanz der zuvor gezeigten Klasse NameForm, um das Formular darzustellen. Die Methode validate_on_submit() des Formulars gibt True zurück, wenn das Formular abgeschickt wurde und die Daten von allen Feldüberprüfern akzeptiert wurden. In allen anderen Fällen gibt validate_on_submit() False zurück. Der Rückgabewert dieser Methode bestimmt, ob das Formular gerendert oder bearbeitet werden muss.

Wenn ein Benutzer zum ersten Mal zur Anwendung navigiert, erhält der Server eine GET Anfrage ohne Formulardaten, so dass validate_on_submit() False zurückgibt. Der Body der if Anweisung wird übersprungen und die Anfrage wird durch das Rendern der Vorlage bearbeitet, die das Formularobjekt und die name Variable, die auf None gesetzt ist, als Argumente erhält. Die Benutzer sehen nun das Formular im Browser angezeigt.

Wenn das Formular vom Benutzer abgeschickt wird, erhält der Server eine POST Anfrage mit den Daten. Der Aufruf von validate_on_submit() ruft den DataRequired() Validator auf, der mit dem Namensfeld verbunden ist. Wenn der Name nicht leer ist, akzeptiert der Validator ihn und validate_on_submit() gibt True zurück. Jetzt ist der vom Benutzer eingegebene Name als data Attribut des Feldes zugänglich. Im Textkörper der Anweisung if wird dieser Name der lokalen Variable name zugewiesen und das Formularfeld wird gelöscht, indem das Attribut data auf eine leere Zeichenkette gesetzt wird, so dass das Feld leer ist, wenn das Formular wieder auf der Seite dargestellt wird. Der render_template() Aufruf in der letzten Zeile rendert die Vorlage, aber dieses Mal enthält das name Argument den Namen aus dem Formular, so dass die Begrüßung personalisiert wird.

Tipp

Wenn du das Git-Repository der Anwendung auf GitHub geklont hast, kannst du git checkout 4a ausführen, um diese Version der Anwendung zu testen.

Abbildung 4-1 zeigt, wie das Formular im Browserfenster aussieht, wenn ein Nutzer die Website zum ersten Mal betritt. Wenn der Nutzer einen Namen eingibt, antwortet die Anwendung mit einer personalisierten Begrüßung. Das Formular erscheint immer noch darunter, so dass der Nutzer es auf Wunsch mehrmals mit verschiedenen Namen abschicken kann. Abbildung 4-2 zeigt die Anwendung in diesem Zustand.

Flask-WTF web form
Abbildung 4-1. Flask-WTF Webformular
Web form after submission
Abbildung 4-2. Webformular nach der Übermittlung

Wenn der Benutzer das Formular mit einem leeren Namen absendet, fängt der DataRequired() Validator den Fehler ab, wie in Abbildung 4-3 zu sehen ist. Beachte, wie viele Funktionen automatisch bereitgestellt werden. Dies ist ein großartiges Beispiel für die Leistungsfähigkeit, die gut durchdachte Erweiterungen wie Flask-WTF und Flask-Bootstrap deiner Anwendung verleihen können.

Web form after failed validator
Abbildung 4-3. Webformular nach fehlgeschlagenem Validator

Umleitungen und Benutzersitzungen

Die letzte Version von hello.py hat ein Problem mit der Benutzerfreundlichkeit. Wenn du deinen Namen eingibst und abschickst und dann auf die Schaltfläche "Aktualisieren" in deinem Browser klickst, bekommst du wahrscheinlich eine obskure Warnung, die dich um Bestätigung bittet, bevor du das Formular erneut abschickst. Das passiert, weil Browser die letzte Anfrage wiederholen, die sie gesendet haben, wenn sie aufgefordert werden, eine Seite zu aktualisieren. Wenn es sich bei der letzten Anfrage um eine Anfrage mit Formulardaten handelt, würde eine Aktualisierung zu einer doppelten Übermittlung des Formulars führen, was in fast allen Fällen nicht erwünscht ist. Aus diesem Grund bittet der Browser um eine Bestätigung des Nutzers. POST

Viele Nutzer verstehen diese Warnung des Browsers nicht. Daher gilt es als gute Praxis für Webanwendungen, niemals eine POST Anfrage als letzte Anfrage des Browsers zu hinterlassen.

Dies wird erreicht, indem auf POST Anfragen mit einem Redirect anstelle einer normalen Antwort geantwortet wird. Ein Redirect ist eine besondere Art der Antwort, die eine URL anstelle einer Zeichenkette mit HTML-Code enthält. Wenn der Browser eine Redirect-Antwort erhält, stellt er eine GET -Anfrage für die Redirect-URL, und das ist die Seite, die er anzeigt. Das ist die Seite, die angezeigt wird. Das Laden der Seite kann ein paar Millisekunden länger dauern, weil eine zweite Anfrage an den Server gesendet werden muss, aber ansonsten merkt der Nutzer keinen Unterschied. Jetzt ist die letzte Anfrage eine GET, sodass der Refresh-Befehl wie erwartet funktioniert. Dieser Trick ist als Post/Redirect/Get-Muster bekannt.

Aber dieser Ansatz bringt ein zweites Problem mit sich. Wenn die Anwendung die Anfrage POST bearbeitet, hat sie Zugriff auf den Namen, den der Nutzer in form.name.data eingegeben hat. Sobald diese Anfrage jedoch endet, gehen die Formulardaten verloren. Da die POST Anfrage mit einer Weiterleitung bearbeitet wird, muss die Anwendung den Namen speichern, damit die weitergeleitete Anfrage ihn erhalten und für die eigentliche Antwort verwenden kann.

Anwendungen können sich Dinge von einer Anfrage zur nächsten "merken", indem sie sie in der Benutzersitzung speichern, einer privaten Speicherung, die jedem verbundenen Client zur Verfügung steht. Die Benutzersitzung wurde in Kapitel 2 als eine der Variablen eingeführt, die mit dem Anfragekontext verbunden sind. Sie heißt session und wird wie ein normales Python-Wörterbuch verwendet.

Hinweis

Benutzersitzungen werden standardmäßig in clientseitigen Cookies gespeichert, die mit dem konfigurierten geheimen Schlüssel kryptografisch signiert sind. Jegliche Manipulation des Cookie-Inhalts würde die Signatur ungültig machen und damit die Sitzung ungültig.

Beispiel 4-5 zeigt eine neue Version der index() View-Funktion, die Redirects und Benutzersitzungen implementiert.

Beispiel 4-5. hello.py: Redirects und Benutzersitzungen
from flask import Flask, render_template, session, redirect, url_for

@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html', form=form, name=session.get('name'))

In der vorherigen Version der Anwendung wurde eine lokale Variable name verwendet, um den vom Benutzer in das Formular eingegebenen Namen zu speichern. Diese Variable wird jetzt als session['name'] in der Benutzersitzung gespeichert, damit sie über die Anfrage hinaus erinnert wird.

Anfragen, die gültige Formulardaten enthalten, enden jetzt mit einem Aufruf von redirect(), einer Flask-Hilfsfunktion, die die HTTP-Umleitungsantwort erzeugt. Die Funktion redirect() nimmt die URL, zu der umgeleitet werden soll, als Argument entgegen. Die in diesem Fall verwendete Umleitungs-URL ist die Stamm-URL, so dass die Antwort auch als redirect('/') hätte geschrieben werden können, aber stattdessen wird die in Kapitel 3 vorgestellte URL-Generatorfunktion url_for() von Flask verwendet.

Das erste und einzige erforderliche Argument für url_for() ist der Endpunktname, der interne Name, den jede Route hat. Standardmäßig ist der Endpunkt einer Route der Name der mit ihr verbundenen View-Funktion. In diesem Beispiel ist die View-Funktion, die die Root-URL verwaltet, index(). Der Name von url_for() ist also index.

Die letzte Änderung betrifft die Funktion render_template(), die jetzt das Argument name direkt aus der Sitzung mit session.get('name') abruft. Wie bei regulären Wörterbüchern vermeidet die Verwendung von get() zur Abfrage eines Wörterbuchschlüssels eine Ausnahme für Schlüssel, die nicht gefunden werden. Die Methode get() gibt bei einem fehlenden Schlüssel den Standardwert None zurück.

Tipp

Wenn du das Git-Repository der Anwendung auf GitHub geklont hast, kannst du git checkout 4b ausführen, um diese Version der Anwendung zu testen.

Mit dieser Version der Anwendung kannst du sehen, dass das Aktualisieren der Seite in deinem Browser immer zum erwarteten Verhalten führt.

Nachricht blinkt

Manchmal ist es sinnvoll, dem Nutzer eine Statusmeldung zu geben, nachdem eine Anfrage abgeschlossen ist. Das kann eine Bestätigungsmeldung, eine Warnung oder ein Fehler sein. Ein typisches Beispiel ist, wenn du ein Login-Formular auf einer Website mit einem Fehler abschickst und der Server daraufhin das Login-Formular erneut ausgibt und dir eine Meldung darüber gibt, dass dein Benutzername oder dein Passwort ungültig ist.

Flask enthält diese Funktion als Kernmerkmal. Beispiel 4-6 zeigt, wie die Funktion flash() für diesen Zweck verwendet werden kann.

Beispiel 4-6. hello.py: geblitzte Nachrichten
from flask import Flask, render_template, session, redirect, url_for, flash

@app.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        old_name = session.get('name')
        if old_name is not None and old_name != form.name.data:
            flash('Looks like you have changed your name!')
        session['name'] = form.name.data
        return redirect(url_for('index'))
    return render_template('index.html',
        form = form, name = session.get('name'))

In diesem Beispiel wird jedes Mal, wenn ein Name eingegeben wird, dieser mit dem in der Benutzersitzung gespeicherten Namen verglichen, der dort bei einer früheren Eingabe desselben Formulars gespeichert wurde. Wenn die beiden Namen unterschiedlich sind, wird die Funktion flash() mit einer Nachricht aufgerufen, die in der nächsten Antwort an den Kunden angezeigt wird.

Der Aufruf von flash() reicht nicht aus, um die Meldungen anzuzeigen; die von der Anwendung verwendeten Templates müssen diese Meldungen auch darstellen. Der beste Ort für die Darstellung von Flash-Meldungen ist das Basis-Template, weil es diese Meldungen auf allen Seiten ermöglicht. Flask stellt den Templates eine get_flashed_messages() Funktion zur Verfügung, um die Meldungen abzurufen und darzustellen, wie in Beispiel 4-7 gezeigt.

Beispiel 4-7. templates/base.html: Rendering von geblitzten Nachrichten
{% block content %}
<div class="container">
    {% for message in get_flashed_messages() %}
    <div class="alert alert-warning">
        <button type="button" class="close" data-dismiss="alert">&times;</button>
        {{ message }}
    </div>
    {% endfor %}

    {% block page_content %}{% endblock %}
</div>
{% endblock %}

In diesem Beispiel werden die Meldungen mit den Bootstrap-CSS-Styles für Warnmeldungen dargestellt (eine davon ist in Abbildung 4-4 zu sehen).

Flashed message
Abbildung 4-4. Blinkende Nachricht

Es wird eine Schleife verwendet, weil mehrere Nachrichten in der Warteschlange stehen können, eine für jeden Aufruf von flash() im vorherigen Abfragezyklus. Meldungen, die von get_flashed_messages() abgerufen werden, werden beim nächsten Aufruf dieser Funktion nicht mehr zurückgegeben, so dass geblinkte Meldungen nur einmal erscheinen und dann verworfen werden.

Tipp

Wenn du das Git-Repository der Anwendung auf GitHub geklont hast, kannst du git checkout 4c ausführen, um diese Version der Anwendung zu testen.

Die Möglichkeit, Daten vom Benutzer über Webformulare entgegenzunehmen, ist eine Funktion, die von den meisten Anwendungen benötigt wird, ebenso wie die Möglichkeit, diese Daten in einer permanenten Speicherung abzulegen. Die Verwendung von Datenbanken mit Flask ist das Thema des nächsten Kapitels.

Get Flask Web Development, 2. Auflage now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.