Wie verwendet man Web-Formulare in einer Flask-Anwendung

Der Autor hat die Free and Open Source Fund als Empfänger einer Spende im Rahmen des Write for DOnations Programms ausgewählt.

Einführung

Webformulare, wie Textfelder und Textbereiche, ermöglichen es Benutzern, Daten an Ihre Anwendung zu senden, um eine Aktion auszuführen oder umfangreiche Textbereiche an die Anwendung zu senden. Zum Beispiel könnten Sie in einer Social-Media-Anwendung den Benutzern ein Feld zur Verfügung stellen, in dem sie neue Inhalte zu ihren Seiten hinzufügen können. Ein weiteres Beispiel ist eine Anmeldeseite, auf der Sie dem Benutzer ein Textfeld zur Eingabe ihres Benutzernamens und ein Passwortfeld zur Eingabe ihres Passworts geben würden. Der Server (in diesem Fall Ihre Flask-Anwendung) verwendet die vom Benutzer eingereichten Daten und meldet sich entweder an, wenn die Daten gültig sind, oder antwortet mit einer Nachricht wie Ungültige Anmeldeinformationen!, um dem Benutzer mitzuteilen, dass die eingereichten Daten nicht korrekt sind.

Flask ist ein leichtgewichtiges Python-Web-Framework, das nützliche Tools und Funktionen für die Erstellung von Webanwendungen in der Python-Sprache bietet. In diesem Tutorial erstellen Sie eine kleine Webanwendung, die zeigt, wie Webformulare verwendet werden. Die Anwendung wird eine Seite haben, um Nachrichten anzuzeigen, die in einer Python-Liste gespeichert sind, und eine Seite zum Hinzufügen neuer Nachrichten. Sie werden auch Nachrichtenblitzen verwenden, um Benutzer über einen Fehler zu informieren, wenn sie ungültige Daten einreichen.

Voraussetzungen

Schritt 1 — Nachrichten anzeigen

In diesem Schritt erstellen Sie eine Flask-Anwendung mit einer Indexseite zur Anzeige von Nachrichten, die in einer Liste von Python-Dictionaries gespeichert sind.

Öffnen Sie zunächst eine neue Datei namens app.py zum Bearbeiten:

  1. nano app.py

Fügen Sie den folgenden Code in die app.py-Datei ein, um einen Flask-Server mit einer einzelnen Route zu erstellen:

flask_app/app.py
from flask import Flask, render_template

app = Flask(__name__)

messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]

@app.route('/')
def index():
    return render_template('index.html', messages=messages)

Speichern und schließen Sie die Datei.

In dieser Datei importieren Sie zunächst die Flask-Klasse und die render_template()-Funktion aus dem flask-Paket. Anschließend verwenden Sie die Flask-Klasse, um eine neue Anwendungsinstanz namens app zu erstellen, wobei die spezielle __name__-Variable übergeben wird, die Flask benötigt, um einige Pfade im Hintergrund einzurichten. Das Rendern von Vorlagen wird im Tutorial Wie man Vorlagen in einer Flask-Anwendung verwendet behandelt.

Sie erstellen dann eine globale Python-Liste namens messages, die Python-Dictionaries enthält. Jedes Dictionary hat zwei Schlüssel: title für den Titel der Nachricht und content für den Nachrichteninhalt. Dies ist ein vereinfachtes Beispiel für eine Datenspeichermethode; in einer realen Anwendung würden Sie eine Datenbank verwenden, die die Daten dauerhaft speichert und es Ihnen ermöglicht, sie effizienter zu bearbeiten.

Nachdem du die Python-Liste erstellt hast, verwendest du den @app.route()-Decorator, um eine Ansichtsfunktion namens index() zu erstellen. In dieser Funktion gibst du einen Aufruf der render_template()-Funktion zurück, die Flask anweist, dass die Route eine HTML-Vorlage anzeigen sollte. Du benennst diese Vorlage index.html (du wirst sie später erstellen) und übergibst eine Variable namens messages an sie. Diese Variable enthält die zuvor deklarierte messages-Liste als Wert und stellt sie der HTML-Vorlage zur Verfügung. Ansichtsfunktionen werden im Tutorial Wie man seine erste Webanwendung mit Flask und Python 3 erstellt behandelt.

Erstelle als Nächstes einen templates-Ordner in deinem flask_app-Verzeichnis, in dem Flask nach Vorlagen sucht, und öffne eine Vorlagendatei namens base.html, die Code enthalten wird, den andere Vorlagen erben, um Codewiederholungen zu vermeiden:

  1. mkdir templates
  2. nano templates/base.html

Füge den folgenden Code in die base.html-Datei ein, um die Basisvorlage mit einer Navigationsleiste und einem Inhaltsblock zu erstellen:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Speichere und schließe die Datei.

Dieses Basis-Template enthält all den HTML-Boilerplate, den Sie in Ihren anderen Templates wiederverwenden müssen. Der title-Block wird ersetzt, um einen Titel für jede Seite festzulegen, und der content-Block wird durch den Inhalt jeder Seite ersetzt. Die Navigationsleiste enthält zwei Links, einen für die Indexseite, auf der Sie die url_for()-Hilfsfunktion verwenden, um zur index()-Ansichtsfunktion zu verlinken, und einen für eine Über-Seite, falls Sie sich entscheiden, eine in Ihrer Anwendung einzufügen.

Öffnen Sie als Nächstes ein Template namens index.html. Dies ist das Template, auf das Sie in der app.py-Datei verwiesen haben:

  1. nano templates/index.html

Fügen Sie den folgenden Code hinzu:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Messages {% endblock %}</h1>
    {% for message in messages %}
        <div class='message'>
            <h3>{{ message['title'] }}</h3>
            <p>{{ message['content'] }}</p>
        </div>
    {% endfor %}
{% endblock %}

Speichern und schließen Sie die Datei.

In diesem Code erweitern Sie das base.html-Template und ersetzen den Inhalt des content-Blocks. Sie verwenden eine <h1>-Überschrift, die auch als Titel dient.

Sie verwenden eine Jinja for-Schleife in der Zeile {% for message in messages %}, um jede Nachricht in der messages-Liste zu durchlaufen. Sie verwenden ein <div>-Tag, um den Titel und den Inhalt der Nachricht zu enthalten. Sie zeigen den Titel in einer <h3>-Überschrift und den Inhalt in einem <p>-Tag an.

Während Sie sich in Ihrem flask_app-Verzeichnis mit aktiviertem virtuellen Environment befinden, teilen Sie Flask mit, dass die Anwendung (app.py in diesem Fall) über die FLASK_APP-Umgebungsvariable verwendet wird:

  1. export FLASK_APP=app

Dann setze die Umgebungsvariable FLASK_ENV auf development, um die Anwendung im Entwicklungsmodus auszuführen und Zugriff auf den Debugger zu erhalten. Weitere Informationen zum Flask-Debugger findest du unter Fehlerbehandlung in einer Flask-Anwendung. Verwende die folgenden Befehle, um dies zu tun (unter Windows verwende set anstelle von export):

  1. export FLASK_ENV=development

Als nächstes führe die Anwendung aus:

  1. flask run

Mit dem laufenden Entwicklungsserver besuche die folgende URL mit deinem Browser:

http://127.0.0.1:5000/

Du siehst die Nachrichten in der messages Liste auf der Indexseite angezeigt:

Nachdem du deine Webanwendung eingerichtet und die Nachrichten angezeigt hast, benötigst du eine Möglichkeit, mit der Benutzer neue Nachrichten zur Indexseite hinzufügen können. Dies geschieht über Webformulare, die du im nächsten Schritt einrichten wirst.

Schritt 2 — Einrichten von Formularen

In diesem Schritt erstellst du eine Seite in deiner Anwendung, die es Benutzern ermöglicht, neue Nachrichten über ein Webformular in die Nachrichtenliste einzufügen.

Lasse den Entwicklungsserver laufen und öffne ein neues Terminalfenster.

Öffne zunächst deine app.py Datei:

  1. nano app.py

Füge die folgende Route ans Ende der Datei hinzu:

flask_app/app.py
# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

Speichere und schließe die Datei.

Diese /create-Route hat den methods-Parameter mit dem Tupel ('GET', 'POST'), um sowohl GET– als auch POST-Anfragen zu akzeptieren. GET und POST sind HTTP-Methoden. Standardmäßig werden nur GET-Anfragen akzeptiert, die zum Abrufen von Daten verwendet werden, z. B. um vom Server eine Indexseite oder eine About-Seite anzufordern. POST-Anfragen werden verwendet, um Daten an eine bestimmte Route zu übermitteln, was oft die Daten auf dem Server ändert.

In diesem Beispiel fordern Sie die create-Seite mit einer GET-Anfrage an. Die Create-Seite wird ein Webformular mit Eingabefeldern und einer Submit-Schaltfläche enthalten. Wenn ein Benutzer das Webformular ausfüllt und auf die Submit-Schaltfläche klickt, wird eine POST-Anfrage an die /create-Route gesendet. Dort verarbeiten Sie die Anfrage, validieren die übermittelten Daten, um sicherzustellen, dass der Benutzer kein leeres Formular eingereicht hat, und fügen sie der messages-Liste hinzu.

Die create()-Ansichtsfunktion erledigt derzeit nur eine Sache: Sie rendert eine Vorlage namens create.html, wenn sie eine reguläre GET-Anfrage erhält. Sie erstellen nun diese Vorlage und bearbeiten die Funktion im nächsten Schritt, um POST-Anfragen zu verarbeiten.

Öffnen Sie eine neue Vorlagendatei namens create.html:

  1. nano templates/create.html

Fügen Sie den folgenden Code hinzu:

flask_app/templates/create.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Add a New Message {% endblock %}</h1>
    <form method="post">
        <label for="title">Title</label>
        <br>
        <input type="text" name="title"
               placeholder="Message title"
               value="{{ request.form['title'] }}"></input>
        <br>

        <label for="content">Message Content</label>
        <br>
        <textarea name="content"
                  placeholder="Message content"
                  rows="15"
                  cols="60"
                  >{{ request.form['content'] }}</textarea>
        <br>
        <button type="submit">Submit</button>
    </form>
{% endblock %}

Speichern und schließen Sie die Datei.

In diesem Code erweiterst du das base.html Template und ersetzt den content Block mit einer <h1> Überschrift, die als Titel für die Seite dient. Im <form> Tag setzt du das method Attribut auf post, sodass die Formulardaten als POST Anfrage an den Server gesendet werden.

Im Formular hast du ein Text-Eingabefeld namens title; dies ist der Name, den du in der Anwendung verwenden wirst, um auf die Titel-Formulardaten zuzugreifen. Du gibst dem <input> Tag einen value von {{ request.form['title'] }}. Dies ist nützlich, um die Daten, die der Benutzer eingibt, wiederherzustellen, sodass sie nicht verloren gehen, wenn etwas schief geht. Wenn der Benutzer beispielsweise vergisst, den erforderlichen content Textbereich auszufüllen, wird eine Anfrage an den Server gesendet und eine Fehlermeldung wird als Antwort zurückkommen, aber die Daten im Titel gehen nicht verloren, da sie im globalen request Objekt gespeichert werden und über request.form['title'] zugegriffen werden können.

Nach dem Titel-Eingabefeld fügst du einen Textbereich namens content mit dem Wert {{ request.form['content'] }} hinzu, aus den gleichen Gründen, die zuvor erwähnt wurden.

Zuletzt hast du einen Submit-Button am Ende des Formulars.

Jetzt, mit dem laufenden Entwicklungsserver, navigiere mit deinem Browser zur /create Route:

http://127.0.0.1:5000/create

Du wirst eine „Neue Nachricht hinzufügen“ Seite sehen, mit einem Eingabefeld für den Nachrichtentitel, einem Textbereich für den Inhalt der Nachricht und einem Submit-Button.

Dieses Formular sendet eine POST-Anfrage an Ihre create()-Ansichtsfunktion. Allerdings gibt es bisher keinen Code, der eine POST-Anfrage verarbeitet, daher passiert nichts, nachdem das Formular ausgefüllt und abgeschickt wurde. Im nächsten Schritt werden Sie die eingehende POST-Anfrage behandeln, wenn ein Formular abgeschickt wird. Sie werden überprüfen, ob die übermittelten Daten gültig sind (nicht leer) und den Nachrichtentitel und den Inhalt zur messages-Liste hinzufügen.

Schritt 3 — Behandlung von Formularanfragen

In diesem Schritt werden Sie Formularanfragen auf der Anwendungsseite behandeln. Sie greifen auf die vom Benutzer über das im vorherigen Schritt erstellte Formular übermittelten Daten zu und fügen sie der Nachrichtenliste hinzu. Sie werden auch Nachrichtenblitzen verwenden, um Benutzer zu informieren, wenn sie ungültige Daten übermitteln. Die Blitznachricht wird nur einmal angezeigt und verschwindet bei der nächsten Anfrage (zum Beispiel, wenn Sie zu einer anderen Seite navigieren).

Öffnen Sie die app.py-Datei zur Bearbeitung:

  1. nano app.py

Importieren Sie zunächst Folgendes aus dem Flask-Framework:

  • Das globale request-Objekt, um auf die eingehenden Anfragedaten zuzugreifen, die über das im letzten Schritt erstellte HTML-Formular übermittelt werden.
  • Die url_for() Funktion zur Generierung von URLs.
  • Die flash() Funktion zum Anzeigen einer Nachricht, wenn eine Anfrage verarbeitet wird (um dem Benutzer mitzuteilen, dass alles gut gelaufen ist, oder um ihn über ein Problem zu informieren, wenn die übermittelten Daten ungültig sind).
  • Die redirect() Funktion zum Weiterleiten des Clients an eine andere Stelle.

Fügen Sie diese Importe in die erste Zeile der Datei ein:

flask_app/app.py
from flask import Flask, render_template, request, url_for, flash, redirect

# ...

Die flash() Funktion speichert flackernde Nachrichten im Browser-Session des Clients, was das Setzen eines geheimen Schlüssels erfordert. Dieser geheime Schlüssel wird verwendet, um Sessions zu sichern, die Flask dazu befähigen, Informationen von einer Anfrage zur nächsten zu merken, wie z.B. von der neuen Nachrichtenseite zur Indexseite. Der Benutzer kann auf die in der Session gespeicherten Informationen zugreifen, aber sie nicht ändern, es sei denn, er hat den geheimen Schlüssel, daher sollten Sie niemals erlauben, dass jemand auf Ihren geheimen Schlüssel zugreift. Weitere Informationen finden Sie in der Flask-Dokumentation für Sessions.

Der geheime Schlüssel sollte eine lange zufällige Zeichenfolge sein. Sie können einen geheimen Schlüssel generieren, indem Sie das os-Modul mit der os.urandom()-Methode verwenden, die eine Zeichenfolge zufälliger Bytes zurückgibt, die für kryptografische Zwecke geeignet ist. Um eine zufällige Zeichenfolge damit zu erhalten, öffnen Sie ein neues Terminal und starten Sie die Python-Interaktivshell mit dem folgenden Befehl:

  1. python

Importieren Sie im Python-Interaktivshell das os-Modul aus der Standardbibliothek und rufen Sie die os.urandom()-Methode wie folgt auf:

  1. import os
  2. os.urandom(24).hex()

Sie erhalten eine Zeichenfolge ähnlich der folgenden:

Output
'df0331cefc6c2b9a5d0208a726a5d1c0fd37324feba25506'

Sie können die erhaltene Zeichenfolge als Ihren geheimen Schlüssel verwenden.

Um den geheimen Schlüssel festzulegen, fügen Sie eine SECRET_KEY-Konfiguration zu Ihrer Anwendung über das app.config-Objekt hinzu. Fügen Sie sie direkt nach der app-Definition hinzu, bevor Sie die messages-Variable definieren:

flask_app/app.py

# ...
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'


messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]
# ...

Ändern Sie als Nächstes die create()-Ansichtsfunktion genau wie folgt:

flask_app/app.py
# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        elif not content:
            flash('Content is required!')
        else:
            messages.append({'title': title, 'content': content})
            return redirect(url_for('index'))

    return render_template('create.html')

In der if-Anweisung stellen Sie sicher, dass der nachfolgende Code nur ausgeführt wird, wenn die Anfrage eine POST-Anfrage ist, über den Vergleich request.method == 'POST'.

Dann extrahieren Sie den eingereichten Titel und Inhalt aus dem request.form Objekt, das Ihnen Zugriff auf die Formulardaten in der Anfrage gibt. Wenn der Titel nicht angegeben ist, wäre die Bedingung if not title erfüllt. In diesem Fall zeigen Sie dem Benutzer eine Nachricht an, die ihn darüber informiert, dass ein Titel erforderlich ist, indem Sie die flash() Funktion verwenden. Dies fügt die Nachricht einer Liste der geflasheden Nachrichten hinzu. Später werden diese Nachrichten als Teil der base.html Vorlage auf der Seite angezeigt. In ähnlicher Weise wird die Bedingung elif not content erfüllt, wenn der Inhalt nicht angegeben ist. Wenn dies der Fall ist, fügen Sie die 'Content is required!' Nachricht zur Liste der geflasheden Nachrichten hinzu.

Wenn der Titel und der Inhalt der Nachricht ordnungsgemäß eingereicht werden, verwenden Sie die Zeile messages.append({'title': title, 'content': content}), um ein neues Wörterbuch zur messages Liste hinzuzufügen, mit dem Titel und Inhalt, den der Benutzer bereitgestellt hat. Dann verwenden Sie die redirect() Funktion, um die Benutzer zur Indexseite umzuleiten. Sie verwenden die url_for() Funktion, um zur Indexseite zu verlinken.

Speichern und schließen Sie die Datei.

Navigieren Sie nun zur /create Route mit Ihrem Webbrowser:

http://127.0.0.1:5000/create

Füllen Sie das Formular mit einem von Ihnen gewählten Titel und einem Inhalt aus. Sobald Sie das Formular absenden, sehen Sie die neue Nachricht auf der Indexseite aufgelistet.

Zuletzt werden Sie die geflasheden Nachrichten anzeigen und einen Link für die „Neue Nachricht“-Seite zum Navigationsbalken in der base.html Vorlage hinzufügen, um einfachen Zugriff auf diese neue Seite zu haben. Öffnen Sie die Basisvorlagendatei:

  1. nano templates/base.html

Bearbeiten Sie die Datei, indem Sie ein neues `<a>`-Tag nach dem FlaskApp-Link in der Navigationsleiste innerhalb des `<nav>`-Tags hinzufügen. Fügen Sie dann direkt über dem `content`-Block eine neue `for`-Schleife hinzu, um die flashed messages unterhalb der Navigationsleiste anzuzeigen. Diese Nachrichten sind in der speziellen `get_flashed_messages()`-Funktion verfügbar, die Flask bereitstellt. Fügen Sie dann jedem Nachrichtenelement ein `class`-Attribut namens `alert` hinzu und geben Sie ihm einige CSS-Eigenschaften innerhalb des `<style>`-Tags:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

        .alert {
            padding: 20px;
            margin: 5px;
            color: #970020;
            background-color: #ffd5de;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% for message in get_flashed_messages() %}
            <div class="alert">{{ message }}</div>
        {% endfor %}
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Speichern und schließen Sie die Datei und laden Sie dann `https://127.0.0.1:5000` in Ihrem Browser neu. Die Navigationsleiste wird nun ein „Create“-Element haben, das zur `/create`-Route führt.

Um zu sehen, wie Flash-Nachrichten funktionieren, gehen Sie zur „Create“-Seite und klicken Sie auf die Schaltfläche „Submit“, ohne die beiden Felder auszufüllen. Sie erhalten eine Nachricht, die wie folgt aussieht:

Gehen Sie zurück zur Indexseite und Sie werden sehen, dass die Flash-Nachrichten unterhalb der Navigationsleiste verschwinden, obwohl sie als Teil der Basisvorlage angezeigt werden. Wenn es keine Flash-Nachrichten wären, würden sie auch auf der Indexseite angezeigt, da sie ebenfalls von der Basisvorlage erben.

Versuche das Formular mit einem Titel, aber ohne Inhalt, einzureichen. Du wirst die Nachricht “Content is required!” sehen. Klicke auf den FlaskApp-Link in der Navigationsleiste, um zur Indexseite zurückzukehren, und dann auf die Zurück-Schaltfläche, um zur Create-Seite zurückzukommen. Du wirst feststellen, dass die Nachricht noch da ist. Dies funktioniert nur, wenn du auf die Zurück-Schaltfläche klickst, da es die vorherige Anfrage speichert. Ein Klick auf den Create-Link in der Navigationsleiste sendet eine neue Anfrage, die das Formular leert und dadurch die gesendete Nachricht verschwinden lässt.

Du weißt jetzt, wie du Benutzereingaben entgegennehmen, diese validieren und einer Datenquelle hinzufügen kannst.

Hinweis:
Die Nachrichten, die du der messages-Liste hinzufügst, verschwinden, wenn der Server stoppt, da Python-Listen nur im Speicher gespeichert sind. Um deine Nachrichten dauerhaft zu speichern, musst du eine Datenbank wie SQLite verwenden. Schau dir How To Use the sqlite3 Module in Python 3 an, um zu lernen, wie man SQLite mit Python verwendet.

Schlussfolgerung

Du hast eine Flask-Anwendung erstellt, in der Benutzer Nachrichten zu einer Liste von auf der Indexseite angezeigten Nachrichten hinzufügen können. Du hast ein Webformular erstellt, die vom Benutzer über das Formular eingereichten Daten verarbeitet und sie deiner Nachrichtenliste hinzugefügt. Du hast auch Flash-Nachrichten verwendet, um den Benutzer zu informieren, wenn sie ungültige Daten einreichen.

Wenn du mehr über Flask lesen möchtest, schau dir die anderen Tutorials in der Flask-Serie an.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-web-forms-in-a-flask-application