Tutorial

Erstellen einer Webanwendung mit Flask in Python 3

Python FrameworksDevelopmentProgramming Project

Der Autor hat den Free and Open Source Fund dazu ausgewählt, eine Spende im Rahmen des Programms Write for DOnations zu erhalten.

Einführung

Flask ist ein kleines und schlankes Python-Web-Framework mit nützlichen Tools und Funktionen, die das Erstellen von Webanwendungen in Python erleichtern. Es bietet Entwicklern mehr Flexibilität und ist ein besser zugängliches Framework für neue Entwickler, da Sie Webanwendungen schnell unter Verwendung einer einzigen Python-Datei erstellen können. Außerdem ist Flask erweiterbar und setzt keine bestimmte Verzeichnisstruktur oder komplizierte Codebausteine voraus, bevor Sie loslegen können.

Als Teil dieses Tutorials nutzen Sie das Bootstrap-Toolkit, um Ihre Anwendung so zu gestalten, dass sie optisch ansprechender aussieht. Bootstrap wird Ihnen helfen, responsive Webseiten in Ihre Webanwendung zu integrieren, sodass sie problemlos auch mit mobilen Browsern funktioniert, ohne dass Sie dafür eigenen HTML-, CSS- und JavaScript-Code schreiben müssen. Mit dem Toolkit können Sie sich darauf konzentrieren, die Funktionsweise von Flask zu erlernen.

Flask verwendet die Jinja-Vorlagen-Engine für das dynamische Einrichten von HTML-Seiten mit bekannten Python-Konzepten wie Variablen, Schleifen, Listen usw. Sie werden diese Vorlagen im Rahmen dieses Projekts nutzen.

In diesem Tutorial entwickeln Sie einen kleinen Weblog mit Flask und SQLite in Python 3. Benutzer der Anwendung können alle Beiträge in Ihrer Datenbank anzeigen und auf den Titel eines Beitrags klicken, um dessen Inhalt anzuzeigen und bei Bedarf der Datenbank einen neuen Beitrag hinzuzufügen bzw. einen bestehenden Beitrag zu bearbeiten oder zu löschen.

Voraussetzungen

Bevor Sie mit diesem Leitfaden fortfahren, benötigen Sie Folgendes:

Schritt 1 – Installieren von Flask

In diesem Schritt aktivieren Sie Ihre Python-Umgebung und installieren Flask mit dem Package Installer pip.

Wenn Sie Ihre Programmierumgebung noch nicht aktiviert haben, stellen Sie sicher, dass Sie sich in Ihrem Projektverzeichnis befinden (flask_blog) und den folgenden Befehl nutzen, um die Umgebung zu aktivieren:

  • source env/bin/activate

Sobald Ihre Programmierumgebung aktiviert ist, weist Ihre Eingabeaufforderung das Präfix env auf, was wie folgt aussieht:

Dieses Präfix ist ein Hinweis darauf, dass die Umgebung env derzeit aktiv ist; sie trägt möglicherweise einen anderen Namen, je nach dem Namen, den Sie der Umgebung bei der Erstellung gegeben haben.

Anmerkung: Sie können Git, ein System für die Versionskontrolle, verwenden, um den Entwicklungsprozess für Ihr Projekt zu verwalten und zu verfolgen. Um mehr über die Verwendung von Git zu erfahren, lesen Sie unseren Artikel Einleitung zu Installation, Nutzung und Verzweigungen von Git.

Wenn Sie Git verwenden, ist es eine gute Idee, das neu erstellte Verzeichnis env in Ihrer Datei .gitignore zu ignorieren, um eine Verfolgung von Dateien zu vermeiden, die nicht mit dem Projekt in Verbindung stehen.

Nun installieren Sie Python-Pakete und isolieren Ihren Projektcode abseits von der Hauptinstallation des Python-Systems. Sie werden das mithilfe von pip und python tun.

Um Flask zu installieren, führen Sie den folgenden Befehl aus:

  • pip install flask

Sobald die Installation abgeschlossen ist, führen Sie den folgenden Befehl aus, um die Installation zu überprüfen:

  • python -c "import flask; print(flask.__version__)"

Sie nutzen die python-Befehlszeilenschnittstelle mit der Option -c, um Python-Code auszuführen. Als Nächstes importieren Sie das flask-Paket mit import flask und drucken dann die Flask-Version, die über die Variable flask.__version__ verfügbar ist.

Die Ausgabe wird eine Versionsnummer sein, die der folgenden ähnelt:

Output
1.1.2

Sie haben den Projektordner und eine virtuelle Umgebung eingerichtet sowie Flask installiert. Sie können nun mit der Einrichtung Ihrer Basisanwendung fortfahren.

Schritt 2 — Erstellen einer Basisanwendung

Nachdem Sie Ihre Programmierumgebung eingerichtet haben, beginnen Sie nun mit der Verwendung von Flask. In diesem Schritt erstellen Sie eine kleine Webanwendung in einer Python-Datei und führen sie aus, um den Server zu starten. Dadurch werden im Browser verschiedene Informationen angezeigt.

Öffnen Sie in Ihrem Verzeichnis flask_blog eine Datei namens hello.py zum Bearbeiten; verwenden Sie dazu nano oder Ihren bevorzugten Texteditor:

  • nano hello.py

Die Datei hello.py wird als Minimalbeispiel für die Handhabung von HTTP-Anfragen dienen. Darin werden Sie das Flask-Objekt importieren und eine Funktion erstellen, die eine HTTP-Antwort zurückgibt. Schreiben Sie den folgenden Code in hello.py:

flask_blog/hello.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello():
    return 'Hello, World!'

Im vorherigen Codeblock importieren Sie zuerst das Flask-Objekt aus dem flask-Paket. Anschließend nutzen Sie es, um Ihre Flask-Anwendungsinstanz mit dem Namen app zu erstellen. Sie übergeben die spezielle Variable __name__, die den Namen des aktuellen Python-Moduls enthält. Damit wird der Instanz mitgeteilt, wo sie sich befindet. Das ist nötig, da Flask einige Pfade im Hintergrund einrichtet.

Nachdem Sie die Instanz app erstellt haben, verwenden Sie sie zum Handhaben eingehender Webanfragen und zum Senden von Antworten an den Benutzer. @app.route ist ein Decorator, der eine reguläre Python-Funktion in eine Flask-Anzeigefunktion verwandelt. Diese verwandelt den Rückgabewert der Funktion in eine HTTP-Antwort, die von einem HTTP-Client (wie einem Webbrowser) angezeigt wird. Sie übergeben den Wert '/' an @app.route(), um anzugeben, dass diese Funktion auf Webanfragen bezüglich der URL / reagiert. Dabei handelt es sich um die Haupt-URL.

Die Anzeigefunktion hello() gibt die Zeichenfolge 'Hello, World!' als Antwort zurück.

Speichern und schließen Sie die Datei.

Um Ihre Webanwendung auszuführen, teilen Sie Flask zuerst mit, wo sich die Anwendung (in Ihrem Fall die Datei hello.py) befindet. Nutzen Sie dazu die Umgebungsvariable FLASK_APP:

  • export FLASK_APP=hello

Führen Sie sie dann im Entwicklungsmodus mit der Umgebungsvariable FLASK_ENV aus:

  • export FLASK_ENV=development

Führen Sie die Anwendung abschließend mit dem Befehl flask run aus:

  • flask run

Sobald die Anwendung ausgeführt wird, sieht die Ausgabe in etwa wie folgt aus:

Output
* Serving Flask app "hello" (lazy loading) * Environment: development * Debug mode: on * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: 813-894-335

Die vorangehende Ausgabe weist mehrere Informationen auf, zum Beispiel:

  • Der Name der Anwendung, die Sie ausführen.
  • Die Umgebung, in der die Anwendung ausgeführt wird.
  • Debug mode: on bedeutet, dass der Flask-Debugger ausgeführt wird. Das ist bei der Entwicklung nützlich, da wir detaillierte Fehlermeldungen erhalten, wenn etwas schiefgeht. Das erleichtert die Fehlerbehebung.
  • Die Anwendung wird lokal an der URL http://127.0.0.1:5000/ ausgeführt; 127.0.0.1​​ ist die IP-Adresse, die den localhost Ihres Computers darstellt, während :5000 die Portnummer ist.

Öffnen Sie einen Browser und geben Sie die URL http://127.0.0.1:5000/ ein; Sie erhalten die Zeichenfolge Hello, World! als Antwort. Das bestätigt, dass Ihre Anwendung erfolgreich ausgeführt wird.

Warnung Flask verwendet einen einfachen Webserver, um unsere Anwendung in einer Entwicklungsumgebung bereitzustellen. Das bedeutet auch, dass der Flask-Debugger ausgeführt wird, um die Erkennung von Fehlern zu erleichtern. Dieser Entwicklungsserver sollte nicht in Produktionsbereitstellungen verwendet werden. Weitere Informationen finden Sie auf der Seite Deploymment Options in der Flask-Dokumentation. Sie können sich auch dieses Flask-Bereitstellungs-Tutorial ansehen.

Sie können den Entwicklungsserver nun im Terminal laufen lassen und ein anderes Terminalfenster öffnen. Gehen Sie zum Projektordner, in dem sich hello.py befindet, aktivieren Sie die virtuelle Umgebung, setzen Sie die Umgebungsvariablen FLASK_ENV und FLASK_APP und fahren Sie mit den nächsten Schritten fort. (Diese Befehle sind in diesem Schritt zuvor aufgelistet.)

Anmerkung: Beim Öffnen eines neuen Terminals ist es wichtig, die virtuelle Umgebung zu aktivieren und die Umgebungsvariablen FLASK_ENV und FLASK_APP festzulegen.

Wenn bereits ein Entwicklungsserver einer Flask-Anwendung ausgeführt wird, ist es nicht möglich, eine weitere Flask-Anwendung mit dem gleichen Befehl flask run auszuführen. Das liegt daran, dass flask run die Portnummer 5000 standardmäßig verwendet. Sobald sie vergeben ist, ist sie nicht mehr zur Ausführung einer weiteren Anwendung verfügbar. Sie erhalten einen Fehler, der dem folgenden ähnelt:

Output
OSError: [Errno 98] Address already in use

Um dieses Problem zu lösen, stoppen Sie entweder den gerade ausgeführten Server mit STRG+C und führen flask run erneut aus. Wenn Sie beide Server gleichzeitig ausführen möchten, können Sie eine andere Portnummer an das Argument -p übergeben. Um zum Beispiel eine weitere Anwendung an Port 5001 auszuführen, verwenden Sie den folgenden Befehl:

  • flask run -p 5001

Sie verfügen nun über eine kleine Flask-Webabwendung. Sie haben Ihre Anwendung ausgeführt und Informationen im Webbrowser angezeigt. Als Nächstes nutzen Sie in Ihrer Anwendung HTML-Dateien.

Schritt 3 — Verwenden von HTML-Vorlagen

Derzeit zeigt Ihre Anwendung nur eine einfache Meldung ohne HTML an. Webanwendungen nutzen HTML hauptsächlich zum Anzeigen von Informationen für den Besucher. Daher arbeiten Sie nun an der Einbindung von HTML-Dateien in Ihre App, die im Webbrowser angezeigt werden können.

Flask bietet eine render_template()-Hilfsfunktion, die eine Verwendung der Jinja-Vorlagen-Engine ermöglicht. Dadurch wird das Verwalten von HTML wesentlich erleichtert, da Ihr HTML-Code in .html-Dateien geschrieben und in Ihrem HTML-Code Logik verwendet wird. Sie werden diese HTML-Dateien (templates) zum Erstellen aller Ihrer Anwendungsseiten nutzen. Dazu gehören zum Beispiel die Hauptseite, auf der Sie die aktuellen Blogbeiträge anzeigen, die Seite des Blogbeitrags, die Seite, auf der Benutzer einen neuen Beitrag hinzufügen können, und so weiter.

In diesem Schritt erstellen Sie Ihre Flask-Hauptanwendung in einer neuen Datei.

Verwenden Sie zuerst in Ihrem Verzeichnis flask_blog nano oder Ihren bevorzugten Editor, um Ihre Datei app.py zu erstellen und zu bearbeiten. Diese wird den gesamten Code enthalten, den Sie zum Erstellen der Bloganwendung verwenden.

  • nano app.py

In dieser neuen Datei importieren Sie das Flask-Objekt, um eine Flask-Anwendungsinstanz zu erstellen, wie Sie dies zuvor getan haben. Außerdem importieren Sie die render_template()-Hilfsfunktion, mit der Sie im Ordner templates, den Sie gleich erstellen werden, vorhandene HTML-Vorlagendateien rendern können. Die Datei wird eine Einzelansichtfunktion aufweisen, die für die Bearbeitung von Anfragen an die Hauptroute / zuständig ist​​. Fügen Sie den folgenden Inhalt hinzu:

flask_blog/app.py
from flask import Flask, render_template

app = Flask(__name__)

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

Die Ansichtsfunktion index() gibt das Ergebnis des Aufrufs von render_template() mit index.html als Argument zurück. Das teilt render_template() mit, nach einer Datei namens index.html im Ordner templates zu suchen. Sowohl der Ordner als auch die Datei existieren noch nicht. Sie erhalten einen Fehler, wenn Sie die Anwendung an dieser Stelle ausführen würden. Sie werden sie trotzdem ausführen, damit Sie sich mit dieser häufig auftretenden Ausnahme vertraut machen können. Dann beheben Sie die Ausnahme durch Erstellung des erforderlichen Ordners und der Datei.

Speichern und schließen Sie die Datei.

Stoppen Sie den Entwicklungsserver im anderen Terminal, in dem die Anwendung hello ausgeführt wird, mit STRG+C.

Bevor Sie die Anwendung ausführen, stellen Sie sicher, dass Sie den Wert für die Umgebungsvariable FLASK_APP richtig angeben, da Sie nicht mehr die Anwendung hello verwenden:

  • export FLASK_APP=app
  • flask run

Durch Öffnen der URL http://127.0.0.1:5000/ in Ihrem Browser wird die Debugger-Seite angezeigt, die Ihnen mitteilt, dass die Vorlage index.html nicht gefunden wurde. Die Hauptzeile im Code, die für diesen Fehler verantwortlich war, wird hervorgehoben. In diesem Fall ist es die Zeile return render_template('index.html')​.

Wenn Sie auf diese Zeile klicken, zeigt der Debugger weiteren Code an, damit Sie über mehr Kontext zum Lösen des Problems verfügen.

Der Flask-Debugger

Um diesen Fehler zu beheben, erstellen Sie ein Verzeichnis namens templates in Ihrem Verzeichnis flask_blog. Öffnen Sie dann darin eine Datei namens index.html zum Bearbeiten:

  • mkdir templates
  • nano templates/index.html

Fügen Sie anschließend in index.html den folgenden HTML-Code hinzu:

flask_blog/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskBlog</title>
</head>
<body>
   <h1>Welcome to FlaskBlog</h1>
</body>
</html>

Speichern Sie die Datei und navigieren Sie in Ihrem Browser erneut zu http://127.0.0.1:5000/ oder aktualisieren Sie die Seite. Dieses Mal sollte der Browser den Text Welcome to FlaskBlog in einem <h1>-Tag anzeigen.

Zusätzlich zum Ordner templates weisen Flask-Webanwendungen typischerweise einen Ordner static zum Hosting von statischen Dateien auf, wie z. B. CSS-Dateien, JavaScript-Dateien und Bilder, die die Anwendung verwendet.

Sie können eine Stylesheetdatei style.css erstellen, um CSS Ihrer Anwendung hinzuzufügen. Erstellen Sie zuerst ein Verzeichnis namens static im Hauptverzeichnis flask_blog:

  • mkdir static

Erstellen Sie dann ein anderes Verzeichnis namens css im Verzeichnis static, um .css-Dateien zu hosten. Das dient normalerweise der Organisation von statischen Dateien in dedizierten Ordnern. So befinden sich JavaScript-Dateien meist in einem Verzeichnis namens js, Bilder in einem Verzeichnis namens images (oder img) und so weiter. Der folgende Befehl erstellt das Verzeichnis css im Verzeichnis static:

  • mkdir static/css

Öffnen Sie dann eine style.css-Datei im css-Verzeichnis zur Bearbeitung:

  • nano static/css/style.css

Fügen Sie Ihrer Datei style.css die folgende CSS-Regel hinzu:

flask_blog/static/css/style.css
h1 {
    border: 2px #eee solid;
    color: brown;
    text-align: center;
    padding: 10px;
}

Der CSS-Code fügt einen Rahmen hinzu, ändert die Farbe in braun, zentriert den Text und fügt <h1>-Tags ein wenig Abstand hinzu.

Speichern und schließen Sie die Datei.

Öffnen Sie als Nächstes die Vorlagendatei index.html zur Bearbeitung:

  • nano templates/index.html

Sie fügen der Datei style.css im Abschnitt <head> der Vorlagendatei index.html einen Link hinzu:

flask_blog/templates/index.html
. . .
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="{{ url_for('static', filename= 'css/style.css') }}">
    <title>FlaskBlog</title>
</head>
. . .

Hier verwenden Sie die Hilfsfunktion url_for(), um den entsprechenden Ort der Datei zu generieren. Das erste Argument gibt an, dass Sie mit einer statischen Datei verknüpfen, und das zweite Argument ist der Pfad der Datei im static-Verzeichnis.

Speichern und schließen Sie die Datei.

Wenn Sie die Indexseite Ihrer Anwendung aktualisieren, werden Sie bemerken, dass der Text Welcome to FlaskBlog jetzt braun, zentriert und in einen Rahmen eingeschlossen ist.

Sie können die CSS-Sprache verwenden, um den Stil der Anwendung zu verändern und nach Ihrem eigenen Geschmack attraktiver zu gestalten. Wenn Sie jedoch kein Webdesigner sind oder nicht mit CSS vertraut sind, können Sie das Bootstrap-Toolkit verwenden, das anwenderfreundliche Komponenten für die Anpassung des Stils Ihrer Anwendung bereitstellt. In diesem Projekt verwenden wir Bootstrap.

Vielleicht haben Sie sich schon gedacht, dass die Einrichtung einer weiteren HTML-Vorlage eine Wiederholung des größten Teils des HTML-Codes bedeutet, den Sie in der Vorlage index.html bereits geschrieben haben. Sie können mithilfe einer Basisvorlagen-Datei, aus der alle Ihre HTML-Dateien erben werden, unnötige Codewiederholungen vermeiden. Weitere Informationen finden Sie in Vorlagenvererbung in Jinja.

Um eine Basisvorlage einzurichten, erstellen Sie zuerst eine Datei namens base.html in Ihrem Verzeichnis templates:

  • nano templates/base.html

Geben Sie in Ihrer Vorlage base.html den folgenden Code ein:

flask_blog/templates/base.html
<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    <title>{% block title %} {% endblock %}</title>
  </head>
  <body>
    <nav class="navbar navbar-expand-md navbar-light bg-light">
        <a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav">
            <li class="nav-item active">
                <a class="nav-link" href="#">About</a>
            </li>
            </ul>
        </div>
    </nav>
    <div class="container">
        {% block content %} {% endblock %}
    </div>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  </body>
</html>

Speichern und schließen Sie die Datei, sobald Sie die Bearbeitung abgeschlossen haben.

Der größte Teil des Codes im vorherigen Block ist Standard-HTML und Code, der für Bootstrap benötigt wird. Die <meta>-Tags bieten Informationen für den Webbrowser, das <link>-Tag verknüpft die Bootstrap CSS-Dateien und die <script>-Tags sind Links zu JavaScript-Code, der einige zusätzliche Bootstrap-Funktionen bietet. Konsultieren Sie die Bootstrap-Dokumentation, um mehr zu erfahren.

Die folgenden hervorgehobenen Teile sind jedoch für die Jinja-Vorlagen-Engine spezifisch:

  • {% block title %} {% endblock %}: Ein Block, der als Platzhalter für einen Titel dient; Sie werden ihn später in anderen Vorlagen nutzen, um einen benutzerdefinierten Titel für jede Seite in Ihrer Anwendung zu vergeben, ohne den gesamten Abschnitt <head> neu schreiben zu müssen.
  • {{ url_for('index')}}: Ein Funktionsaufruf, der die URL für die Ansichtsfunktion index() zurückgibt. Das unterscheidet sich von dem vorherigen Aufruf url_for(), den Sie verwendet haben, um eine statische CSS-Datei zu verknüpfen. Er weist nur ein Argument auf, bei dem es sich um den Namen der Ansichtsfunktion handelt, und verknüpft mit der Route, die mit der Funktion verbunden ist (anstelle einer statischen Datei).
  • {% block content %} {% endblock %}: Ein weiterer Block, der durch Inhalt ersetzt wird, je nach der untergeordneten Vorlage (Vorlagen, die von base.html erben), die ihn überschreiben wird.

Nachdem Sie nun über eine Basisvorlage verfügen, können Sie sie mithilfe von Vererbung nutzen. Öffnen Sie die Datei index.html:

  • nano templates/index.html

Ersetzen Sie die Inhalte mit Folgendem:

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

{% block content %}
    <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
{% endblock %}

In dieser neuen Version der Vorlage index.html verwenden Sie das {% extends %}-Tag, um von der Vorlage base.html zu erben. Dann erweitern Sie sie, indem Sie den content-Block in der Basisvorlage durch das ersetzen, was innerhalb des content-Blocks im vorherigen Codeblock enthalten ist.

Dieser content-Block enthält ein <h1>-Tag mit dem Text Welcome to FlaskBlog in einem title-Block, der wiederum den ursprünglichen title-Block in der Vorlage base.html durch den Text Welcome to FlaskBlog ersetzt. So müssen Sie den gleichen Text nicht zweimal wiederholen, da er sowohl als Titel für die Seite als auch Überschrift dienen kann, die unterhalb der Navigationsleiste erscheint, geerbt von der Basisvorlage.

Außerdem bietet Ihnen Vererbung mit Vorlagen die Möglichkeit, den HTML-Code, über den Sie in anderen Vorlagen verfügen (in diesem Fall base.html), wiederzuverwenden, ohne ihn jedes Mal wiederholen zu müssen, wenn er benötigt wird.

Speichern und schließen Sie die Datei und aktualisieren Sie die Indexseite in Ihrem Browser. Sie werden Ihre Seite mit einer Navigationsleiste und einem formatierten Titel sehen.

Indexseite mit Bootstrap

Sie haben in Flask HTML-Vorlagen und statische Dateien verwendet. Außerdem haben Sie Bootstrap genutzt, um die Optik Ihrer Seite und eine Basisvorlage anzupassen, um Codewiederholungen zu vermeiden. Im nächsten Schritt richten Sie eine Datenbank ein, die Ihre Anwendungsdaten speichern wird.

Schritt 4 — Einrichten der Datenbank

In diesem Schritt richten Sie eine Datenbank zur Speicherung von Daten ein, d. h. die Blogbeiträge für Ihre Anwendung. Außerdem befüllen Sie die Datenbank mit einigen Beispieleinträgen.

Sie werden eine SQLite-Datenbankdatei verwenden, um Ihre Daten zu speichern, da das Modul sqlite3, das wir zur Interaktion mit der Datenbank verwenden, in der Python-Standardbibliothek einsatzbereit ist. Weitere Informationen zu SQLite finden Sie in diesem Tutorial.

Da Daten in SQLite in Tabellen und Spalten gespeichert werden und Ihre Daten hauptsächlich aus Blogbeiträgen bestehen, müssen Sie zunächst eine Tabelle namens posts mit den erforderlichen Spalten erstellen. Sie werden eine .sql-Datei erstellen, die SQL-Befehle enthält, um die Tabelle posts mit einigen Spalten zu erstellen. Dann verwenden Sie diese Datei zur Erstellung der Datenbank.

Öffnen Sie eine Datei namens schema.sql in Ihrem Verzeichnis flask_blog:

  • nano schema.sql

Geben Sie in dieser Datei die folgenden SQL-Befehle ein:

flask_blog/schema.sql
DROP TABLE IF EXISTS posts;

CREATE TABLE posts (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
    title TEXT NOT NULL,
    content TEXT NOT NULL
);

Speichern und schließen Sie die Datei.

Der erste SQL-Befehl ist DROP TABLE IF EXISTS posts; – damit werden alle bereits vorhandenen Tabellen namens posts gelöscht, damit Sie nicht durcheinander kommen. Beachten Sie, dass bei Nutzung dieser SQL-Befehle stets alle in der Datenbank vorhandenen Inhalte gelöscht werden. Schreiben Sie also keine wichtigen Inhalte in die Webanwendung, bis Sie dieses Tutorial abgeschlossen und mit dem Endergebnis experimentiert haben. Als Nächstes verwenden Sie CREATE TABLE posts zur Erstellung der Tabelle posts mit den folgenden Spalten:

  • id: Eine ganze Zahl, die einen Primärschlüssel darstellt; diesem wird von der Datenbank für jeden Eintrag (also jeden Blogbeitrag) ein eindeutiger Wert zugewiesen.
  • created: Die Zeit, zu der der Blogbeitrag erstellt wurde. NOT NULL bedeutet, dass diese Spalte nicht leer sein darf und der DEFAULT-Wert der CURRENT_TIMESTAMP-Wert ist. Das ist der Zeitpunkt, zu dem der Blogbeitrag der Datenbank hinzugefügt wurde. Genau wie bei id müssen Sie keinen Wert für diese Spalte angeben, da er automatisch ausgefüllt wird.
  • title: Der Titel des Beitrags.
  • content: Der Inhalt des Beitrags.

Nachdem Sie in der Datei schema.sql über ein SQL-Schema verfügen, verwenden Sie es nun zur Erstellung der Datenbank mit einer Python-Datei, die eine SQLite .db-Datenbank generieren wird. Öffnen Sie mit Ihrem bevorzugten Editor eine Datei namens init_db.py im Verzeichnis flask_blog:

  • nano init_db.py

Und fügen Sie dann den folgenden Code hinzu.

flask_blog/init_db.py
import sqlite3

connection = sqlite3.connect('database.db')


with open('schema.sql') as f:
    connection.executescript(f.read())

cur = connection.cursor()

cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
            ('First Post', 'Content for the first post')
            )

cur.execute("INSERT INTO posts (title, content) VALUES (?, ?)",
            ('Second Post', 'Content for the second post')
            )

connection.commit()
connection.close()

Zuerst importieren Sie das Modul sqlite3 und öffnen dann eine Verbindung zu einer Datenbankdatei namens database.db, die erstellt wird, sobald Sie die Python-Datei ausführen. Dann verwenden Sie die Funktion open(), um die Datei schema.sql zu öffnen. Als Nächstes führen Sie ihre Inhalte mit der Methode executescript() aus, die mehrere SQL-Anweisungen auf einmal ausführt. Dadurch wird die Tabelle posts erstellt. Sie erstellen ein Cursor-Objekt, mit dem Sie die Methode execute() verwenden können, um zwei INSERT SQL-Anweisungen auszuführen und Ihrer Tabelle posts zwei Blogbeiträge hinzuzufügen. Schließlich committen Sie die Änderungen und schließen die Verbindung.

Speichern und schließen Sie die Datei und führen Sie sie dann im Terminal mit dem python-Befehl aus:

  • python init_db.py

Sobald die Ausführung der Datei beendet ist, wird in Ihrem Verzeichnis flask_blog eine neue Datei namens database.db angezeigt. Das bedeutet, dass Sie Ihre Datenbank erfolgreich eingerichtet haben.

Im nächsten Schritt rufen Sie die Beiträge ab, die Sie in Ihre Datenbank eingefügt haben, und zeigen sie auf der Homepage Ihrer Anwendung an.

Schritt 5 — Anzeigen aller Beiträge

Nachdem Sie Ihre Datenbank eingerichtet haben, können Sie die Ansichtsfunktion index() nun so ändern, dass sie alle Beiträge anzeigt, die Sie in Ihrer Datenbank haben.

Öffnen Sie die Datei app.py, um die folgenden Änderungen vorzunehmen:

  • nano app.py

Als erste Änderung importieren Sie das Modul sqlite3 an den Anfang der Datei:

flask_blog/app.py
import sqlite3
from flask import Flask, render_template

. . .

Als Nächstes erstellen Sie eine Funktion, die eine Datenbankverbindung erstellt und zurückgibt. Fügen Sie sie direkt nach den Importen hinzu:

flask_blog/app.py
. . .
from flask import Flask, render_template

def get_db_connection():
    conn = sqlite3.connect('database.db')
    conn.row_factory = sqlite3.Row
    return conn

. . .

Diese get_db_connection()-Funktion öffnet eine Verbindung zur Datenbankdatei database.db und legt dann das Attribut row_factory auf sqlite3. Row fest, damit Sie namenbasierten Zugriff auf Spalten erhalten. Das bedeutet, dass die Datenbankverbindung Zeilen zurückgibt, die sich wie reguelmäßige Python-Wörterbücher verhalten. Schließlich gibt die Funktion das Verbindungsobjekt conn zurück, das Sie zum Zugriff auf die Datenbank verwenden werden.

Nach der Definition der get_db_connection()-Funktion ändern Sie die Funktion index(), damit sie wie folgt aussieht:

flask_blog/app.py
. . .

@app.route('/')
def index():
    conn = get_db_connection()
    posts = conn.execute('SELECT * FROM posts').fetchall()
    conn.close()
    return render_template('index.html', posts=posts)

In dieser neuen Version der Funktion index() öffnen Sie zuerst mit der Funktion get_db_connection(), die Sie zuvor definiert haben, eine Datenbankverbindung. Dann führen Sie eine SQL-Abfrage aus, um alle Einträge aus der Tabelle posts auszuwählen. Sie implementieren die Methode fetchall(), um alle Zeilen des Abfrageergebnisses abzurufen. Dadurch wird eine Liste der Beiträge, die Sie der Datenbank im vorherigen Schritt hinzugefügt haben, zurückgegeben.

Sie schließen die Datenbankverbindung mit dem Befehl close() und geben das Ergebnis vom Rendern der Vorlage index.html zurück. Außerdem übergeben Sie das Objekt posts als Argument, das die Ergebnisse enthält, die Sie aus der Datenbank erhalten haben. Das ermöglicht Ihnen, auf die Blogbeiträge in der Vorlage index.html zuzugreifen.

Speichern und schließen Sie die Datei app.py nach Vornahme der Änderungen.

Nachdem Sie die Beiträge, die Sie von der Datenbank abgerufen haben, an die Vorlage index.html übergeben haben, können Sie eine for-Schleife verwenden, um einzelne Beiträge auf Ihrer Indexseite anzuzeigen.

Öffnen Sie die Datei index.html:

  • nano templates/index.html

Ändern Sie sie dann so, dass sie wie folgt aussieht:

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

{% block content %}
    <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
    {% for post in posts %}
        <a href="#">
            <h2>{{ post['title'] }}</h2>
        </a>
        <span class="badge badge-primary">{{ post['created'] }}</span>
        <hr>
    {% endfor %}
{% endblock %}

Hier ist die Syntax {% for post in posts %} eine Jinja-for-Schleife, die einer Python-for-Schleife ähnelt; sie muss allerdings später mit der {% endfor %}-Syntax geschlossen werden. Sie verwenden diese Syntax, um für jedes Element in der Liste posts, die von der Funktion index() in der Zeile return render_template('index.html', posts=posts) übergeben wurde, eine Schleife zu durchlaufen. Innerhalb dieser for-Schleife zeigen Sie den Titel des Beitrags in einer <h2>-Überschrift in einem <a>-Tag an (Sie verwenden dieses Tag später, um Verknüpfungen für die einzelnen Beiträge zu erstellen).

Sie zeigen den Titel an mit einem Literal-Variablen-Trennzeichen ({{ ... }}). Denken Sie daran, dass post ein wörterbuchähnliches Objekt sein wird, damit Sie mit post['title'] auf den Beitragstitel zugreifen können. Außerdem zeigen Sie mit der gleichen Methode das Erstellungsdatum des Beitrags an.

Sobald Sie die Bearbeitung der Datei abgeschlossen haben, speichern und schließen Sie sie. Navigieren Sie dann in Ihrem Browser zur Indexseite. Sie werden die beiden Beiträge, die Sie der Datenbank hinzugefügt haben, auf Ihrer Seite sehen.

Indexseite mit den angezeigten Beiträgen

Nachdem Sie die Ansichtsfunktion index() modifiziert haben, um alle Beiträge, die Sie in der Datenbank haben, auf der Homepage Ihrer Anwendung anzeigen, zeigen Sie nun jeden Beitrag auf einer einzelnen Seite an und ermöglichen es Benutzern, Links zu den einzelnen Beiträgen zu nutzen.

Schritt 6 — Anzeigen eines einzelnen Beitrags

In diesem Schritt erstellen Sie eine neue Flask-Route mit einer Ansichtsfunktion und eine neue HTML-Vorlage zur Anzeige eines einzelnen Blogeintrags anhand seiner ID.

Am Ende dieses Schritts wird die URL http://127.0.0.1:5000/1 eine Seite sein, die den ersten Beitrag anzeigt (weil dieser die ID 1 hat). Die URL http://127.0.0.1:5000/ID zeigt den Beitrag mit der zugehörigen ID-Nummer an, so sie vorhanden ist.

Öffnen Sie app.py zum Bearbeiten:

  • nano app.py

Da Sie in diesem Projekt noch an unterschiedlichen Stellen einen Blogeintrag aus der Datenbank abrufen müssen, erstellen Sie eine Standalone-Funktion namens get_post(). Sie können sie aufrufen, indem Sie ihr eine ID übergeben, und erhalten den Blogbeitrag zurück, der mit der bereitgestellten ID verknüpft ist; oder Sie sorgen dafür, dass Flask mit einer 404 Nicht gefunden-Nachricht antwortet, wenn der Blogbeitrag nicht existiert.

Um mit einer 404-Seite zu antworten, müssen Sie die Funktion abort() aus der Werkzeug-Bibliothek, die zusammen mit Flask installiert wurde, am Anfang der Datei importieren:

flask_blog/app.py
import sqlite3
from flask import Flask, render_template
from werkzeug.exceptions import abort

. . .

Fügen Sie die Funktion get_post() direkt nach der Funktion get_db_connection() hinzu, die Sie im vorherigen Schritt erstellt haben:

flask_blog/app.py
. . .

def get_db_connection():
    conn = sqlite3.connect('database.db')
    conn.row_factory = sqlite3.Row
    return conn


def get_post(post_id):
    conn = get_db_connection()
    post = conn.execute('SELECT * FROM posts WHERE id = ?',
                        (post_id,)).fetchone()
    conn.close()
    if post is None:
        abort(404)
    return post

. . .

Diese neue Funktion verfügt über ein post_id-Argument, das bestimmt, welcher Blogbeitrag zurückgegeben wird.

Innerhalb der Funktion verwenden Sie die Funktion get_db_connection() zum Öffnen einer Datenbankverbindung und Ausführen einer SQL-Abfrage, um den Blogbeitrag zu erhalten, der mit dem angegebenen post_id-Wert verknüpft ist. Sie fügen die Methode fetchone() hinzu, um das Ergebnis zu erhalten und in der Variable post zu speichern. Dann schließen Sie die Verbindung. Wenn die Variable post den Wert None (Keine) hat, was bedeutet, dass in der Datenbank kein Ergebnis gefunden wird, verwenden Sie die Funktion abort(), die Sie zuvor importiert haben, um mit einem 404-Fehlercode zu reagieren; die Ausführung der Funktion wird beendet. Wenn jedoch ein Beitrag gefunden wurde, geben Sie den Wert der Variable post zurück.

Fügen Sie als Nächstes die folgende Ansichtsfunktion am Ende der Datei app.py hinzu:

flask_blog/app.py
. . .

@app.route('/<int:post_id>')
def post(post_id):
    post = get_post(post_id)
    return render_template('post.html', post=post)

In dieser neuen Ansichtsfunktion fügen Sie eine Variablenregel <int:post_id> hinzu, um anzugeben, dass der Teil nach dem Schrägstrich (/) eine positive ganze Zahl ist (markiert mit dem int-Konverter), die Sie in Ihrer Ansichtsfunktion aufrufen müssen. Flask erkennt das und übergibt ihren Wert an das Schlüsselwortargument post_id Ihrer post()-Ansichtsfunktion. Dann verwenden Sie die Funktion get_post(), um den Blogbeitrag abzurufen, der mit der angegebenen ID verknüpft ist, und speichern das Ergebnis in der Variable post, die Sie an eine post.html-Vorlage, die Sie bald erstellen werden, übergeben.

Speichern Sie die Datei app.py und öffnen Sie eine neue post.html-Vorlagendatei zur Bearbeitung:

  • nano templates/post.html

Geben Sie in dieser neuen post.html-Datei den folgenden Code ein. Das wird ähnlich aussehen wie bei der Datei index.html; es wird jedoch nur ein einziger Blogbeitrag angezeigt, und zudem mit dem Inhalt des Beitrags:

flask_blog/templates/post.html
{% extends 'base.html' %}

{% block content %}
    <h2>{% block title %} {{ post['title'] }} {% endblock %}</h2>
    <span class="badge badge-primary">{{ post['created'] }}</span>
    <p>{{ post['content'] }}</p>
{% endblock %}

Sie fügen den title-Block hinzu, den Sie in der Vorlage base.html definiert haben, um den Titel der Seite an den Titel des Beitrags anzupassen, der gleichzeitig in einer <h2>-Überschrift angezeigt wird.

Speichern und schließen Sie die Datei.

Sie können nun zu den folgenden URLs navigieren, um die beiden Beiträge, die Sie in Ihrer Datenbank haben, sowie eine Seite anzuzeigen, die dem Benutzer mitteilt, dass der angeforderte Blogbeitrag nicht gefunden wurde (da bisher kein Beitrag mit der ID-Nummer 3 vorhanden ist):

http://127.0.0.1:5000/1
http://127.0.0.1:5000/2
http://127.0.0.1:5000/3

Zurück auf der Indexseite verknüpfen Sie jeden Titel eines Beitrags mit seiner jeweiligen Seite. Dazu verwenden Sie die Funktion url_for(). Öffnen Sie zuerst die Vorlage index.html zur Bearbeitung:

  • nano templates/index.html

Ändern Sie dann den Wert des Attributs href von # in {{ url_for('post', post_id=post['id']) }}, damit die for-Schleife genau wie folgt aussieht:

flask_blog/templates/index.html
{% for post in posts %}
    <a href="{{ url_for('post', post_id=post['id']) }}">
        <h2>{{ post['title'] }}</h2>
    </a>
    <span class="badge badge-primary">{{ post['created'] }}</span>
    <hr>
{% endfor %}

Hier übergeben Sie 'post' an die Funktion url_for() als erstes Argument. Das ist der Name der post()-Ansichtsfunktion; da sie ein post_id-Argument akzeptiert, geben Sie den Wert post['id']. Die Funktion url_for() gibt für jeden Beitrag auf Grundlage seiner ID die richtige URL zurück.

Speichern und schließen Sie die Datei.

Die Links auf der Indexseite funktionieren nun wie erwartet. Damit haben Sie die Erstellung des Teils der Anwendung abgeschlossen, der für die Anzeige der Blogbeiträge in Ihrer Datenbank verantwortlich ist. Als Nächstes fügen Sie die Möglichkeit zur Erstellung, Bearbeitung und Löschung von Blogbeiträgen zu Ihrer Anwendung hinzu.

Schritt 7 — Bearbeiten von Beiträgen

Nachdem Sie die Anzeige der Blogbeiträge, die in der Datenbank vorhanden sind, in der Webanwendung abgeschlossen haben, müssen Sie es den Benutzern Ihrer Anwendung nun ermöglichen, neue Blogbeiträge zu schreiben und der Datenbank hinzuzufügen, vorhandene Beiträge zu bearbeiten und unnötige Blogbeiträge zu löschen.

Erstellen eines neuen Beitrags

Bislang verfügen Sie über eine Anwendung, die die Beiträge in Ihrer Datenbank anzeigt, aber keine Möglichkeit zum Hinzufügen eines neuen Beitrags, es sei denn, Sie verbinden sich direkt mit der SQLite-Datenbank und fügen manuell einen Beitrag hinzu. In diesem Abschnitt richten Sie eine Seite ein, auf der Sie einen Beitrag erstellen können, indem Sie den Titel und den Inhalt bereitstellen.

Öffnen Sie die Datei app.py zur Bearbeitung:

  • nano app.py

Zuerst importieren Sie Folgendes aus dem Flask-Framework:

  • Das globale request-Objekt für den Zugriff auf eingehende Anfragedaten, die über ein HTML-Formular übermittelt werden.
  • Die Funktion url_for() zur Erstellung von URLs.
  • Die flash()-Funktion zur Anzeige einer Meldung, wenn eine Anfrage verarbeitet wird.
  • Die Funktion redirect() zum Umleiten des Clients an einen anderen Ort.

Fügen Sie die Importe wie folgt in Ihre Datei ein:

flask_blog/app.py
import sqlite3
from flask import Flask, render_template, request, url_for, flash, redirect
from werkzeug.exceptions import abort

. . .

Die flash()-Funktion speichert geflashte Nachrichten in der Browsersitzung des Clients, was die Einrichtung eines geheimen Schlüssels erfordert. Dieser geheime Schlüssel dient zur Sicherung von Sitzungen, sodass sich Flask Informationen von einer Anfrage zu einer anderen merken kann, zum Beispiel beim Navigieren von der Seite für neue Beiträge zur Indexseite. Der Benutzer kann auf die in der Sitzung gespeicherten Daten zugreifen, sie aber nicht ändern, es sei denn, er verfügt über den geheimen Schlüssel; das bedeutet, dass Sie niemandem Zugriff auf Ihren geheimen Schlüssel gewähren dürfen. Weitere Informationen finden Sie in der Flask-Dokumentation für Sitzungen.

Um einen geheimen Schlüssel einzurichten, fügen Sie Ihrer Anwendung eine SECRET_KEY-Konfiguration über das Objekt app.config hinzu. Fügen Sie sie unmittelbar nach der app-Definition hinzu, bevor Sie die Ansichtsfunktion index() definieren:

flask_blog/app.py
. . .
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'


@app.route('/')
def index():
    conn = get_db_connection()
    posts = conn.execute('SELECT * FROM posts').fetchall()
    conn.close()
    return render_template('index.html', posts=posts)

. . .

Denken Sie daran, dass der geheime Schlüssel eine lange Zufallszeichenfolge sein sollte.

Nach der Einrichtung eines geheimen Schlüssels erstellen Sie eine Ansichtsfunktion, die eine Vorlage rendern wird, um ein Formular anzuzeigen, das Sie zum Erstellen eines neuen Blogbeitrags ausfüllen können. Fügen Sie diese neue Funktion am Ende der Datei hinzu:

flask_blog/app.py
. . .

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

Dadurch wird eine /create-Route erstellt, die sowohl GET- als auch POST-Anfragen akzeptiert. GET-Anfragen werden standardmäßig akzeptiert. Um auch POST-Anfragen zu akzeptieren, die vom Browser beim Übermitteln von Formularen gesendet werden, übergeben Sie ein Tupel mit den akzeptierten Arten von Anfragen an das methods-Argument des @app.route()-Decorators.

Speichern und schließen Sie die Datei.

Um die Vorlage zu erstellen, öffnen Sie eine Datei namens create.html in Ihrem Ordner templates:

  • nano templates/create.html

Fügen Sie in dieser neuen Datei den folgenden Code hinzu:

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

{% block content %}
<h1>{% block title %} Create a New Post {% endblock %}</h1>

<form method="post">
    <div class="form-group">
        <label for="title">Title</label>
        <input type="text" name="title"
               placeholder="Post title" class="form-control"
               value="{{ request.form['title'] }}"></input>
    </div>

    <div class="form-group">
        <label for="content">Content</label>
        <textarea name="content" placeholder="Post content"
                  class="form-control">{{ request.form['content'] }}</textarea>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Submit</button>
    </div>
</form>
{% endblock %}

Der größte Teil dieses Codes ist Standard-HTML. Er zeigt ein Eingabefeld für den Titel des Beitrags, einen Textbereich für den Inhalt des Beitrags und eine Schaltfläche zum Übermitteln des Formulars an.

Der Wert der Beitragstiteleingabe ist {{ request.form['title'] }} und der Textbereich hat den Wert {{ request.form['content'] }}; das sorgt dafür, dass die eingegebenen Daten nicht verloren gehen, wenn etwas schiefläuft. Wenn Sie zum Beispiel einen langen Beitrag verfassen und vergessen, ihm einen Titel zu geben, wird Ihnen eine Meldung angezeigt, die Sie daran erinnert, dass der Titel erforderlich ist. Das geschieht, ohne dass Sie den geschriebenen Beitrag verlieren, da er im globalen request-Objekt gespeichert wird, auf das Sie in Ihren Vorlagen Zugriff haben.

Nachdem der Entwicklungsserver ausgeführt wird, verwenden Sie nun Ihren Browser, um zur Route /create zu navigieren:

http://127.0.0.1:5000/create

Sie werden eine Seite für Create a New Post mit einem Feld für Titel und Inhalt sehen.

Seite zum Erstellen eines neuen Beitrags

Dieses Formular übermittelt eine POST-Anfrage an Ihre create()-Funktion. In der Funktion gibt es jedoch noch keinen Code, um eine POST-Anfrage zu bearbeiten; also wird nach dem Ausfüllen und Übermitteln des Formulars nichts geschehen.

Sie werden die eingehende POST-Anfrage bearbeiten, wenn ein Formular übermittelt wird. Das tun Sie in der create()-Ansichtsfunktion. Sie können die POST-Anfrage separat bearbeiten, indem Sie den Wert von request.method überprüfen. Wenn der Wert auf 'POST' festgelegt ist, bedeutet das, dass die Anfrage eine POST-Anfrage ist. Dann fahren Sie mit dem Extrahieren der übermittelten Daten sowie dem Validieren und Einfügen der Daten in Ihre Datenbank fort.

Öffnen Sie die Datei app.py zur Bearbeitung:

  • nano app.py

Ändern Sie die create()-Ansichtsfunktion, damit sie genau wie folgt aussieht:

flask_blog/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!')
        else:
            conn = get_db_connection()
            conn.execute('INSERT INTO posts (title, content) VALUES (?, ?)',
                         (title, content))
            conn.commit()
            conn.close()
            return redirect(url_for('index'))

    return render_template('create.html')

Stellen Sie in der if-Anweisung sicher, dass der darauf folgende Code nur ausgeführt wird, wenn die Anfrage eine POST-Anfrage ist. Nutzen Sie dazu den Vergleich request.method == 'POST'.

Dann extrahieren Sie den übermittelten Titel und Inhalt aus dem request.from-Objekt, das Ihnen Zugriff auf die Formulardaten in der Anfrage bietet. Wenn der Titel nicht angegeben ist, wäre die Bedingung if not title erfüllt. In dem Fall wird dem Benutzer eine Meldung angezeigt, die ihm mitteilt, dass ein Titel erforderlich ist. Wenn der Titel hingegen angegeben ist, öffnen Sie eine Verbindung mit der Funktion get_db_connection() und fügen den Titel und Inhalt, die Sie erhalten haben, in die Tabelle posts ein.

Dann übergeben Sie die Änderungen mit „commit“ an die Datenbank und schließen die Verbindung. Nachdem Sie den Blogbeitrag in die Datenbank eingefügt haben, leiten Sie den Client mit der redirect()-Funktion auf die Indexseite um. Dazu übergeben Sie ihr die von der Funktion url_for() mit dem Wert 'index' als Argument generierte URL.

Speichern und schließen Sie die Datei.

Navigieren Sie nun mit Ihrem Webbrowser zur Route /create:

http://127.0.0.1:5000/create

Füllen Sie das Formular mit einem Titel Ihrer Wahl und einem Inhalt aus. Sobald Sie das Formular übermitteln, sehen Sie, dass der neue Beitrag auf der Indexseite aufgelistet wird.

Schließlich zeigen Sie geflashte Nachrichten an und fügen zur Navigationsleiste in der Vorlage base.html eine Verknüpfung hinzu, um einfachen Zugriff auf diese neue Seite zu ermöglichen. Öffnen Sie die Vorlagendatei:

  • nano templates/base.html

Bearbeiten Sie die Datei, indem Sie ein neues <li>-Tag nach dem Link About im Tag <nav> hinzufügen. Fügen Sie dann direkt über dem content-Block eine neue for-Schleife hinzu, um die geflashten Nachrichten unterhalb der Navigationsleiste anzuzeigen. Diese Nachrichten sind in der speziellen Funktion get_flashed_messages() von Flask verfügbar:

flask_blog/templates/base.html
<nav class="navbar navbar-expand-md navbar-light bg-light">
    <a class="navbar-brand" href="{{ url_for('index')}}">FlaskBlog</a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
        <li class="nav-item">
            <a class="nav-link" href="#">About</a>
        </li>
        <li class="nav-item">
            <a class="nav-link" href="{{url_for('create')}}">New Post</a>
        </li>
        </ul>
    </div>
</nav>
<div class="container">
    {% for message in get_flashed_messages() %}
        <div class="alert alert-danger">{{ message }}</div>
    {% endfor %}
    {% block content %} {% endblock %}
</div>

Speichern und schließen Sie die Datei. Die Navigationsleiste verfügt nun über ein Element New Post, das mit der Route /create verknüpft ist.

Bearbeiten eines Beitrags

Damit Ihr Blog aktuell bleibt, müssen Sie Ihre vorhandenen Beiträge bearbeiten können. Dieser Abschnitt führt Sie durch die Erstellung einer neuen Seite in Ihrer Anwendung, um das Bearbeiten eines Beitrags zu vereinfachen.

Zuerst fügen Sie der Datei app.py eine neue Route hinzu. Ihre Ansichtsfunktion empfängt die ID des Beitrags, der bearbeitet werden soll; die URL wird im Format /post_id/edit vorliegen, wobei die Variable post_id die ID des Beitrags ist. Öffnen Sie die Datei app.py zur Bearbeitung:

  • nano app.py

Fügen Sie als Nächstes die folgende Ansichtsfunktion edit() am Ende der Datei hinzu: Die Bearbeitung eines bestehenden Beitrags ähnelt der Erstellung eines neuen Beitrags. Daher wird diese Ansichtsfunktion ähnlich aussehen wie die create()-Ansichtsfunktion:

flask_blog/app.py
. . .

@app.route('/<int:id>/edit', methods=('GET', 'POST'))
def edit(id):
    post = get_post(id)

    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        else:
            conn = get_db_connection()
            conn.execute('UPDATE posts SET title = ?, content = ?'
                         ' WHERE id = ?',
                         (title, content, id))
            conn.commit()
            conn.close()
            return redirect(url_for('index'))

    return render_template('edit.html', post=post)

Der Beitrag, den Sie bearbeiten, wird von der URL bestimmt; Flask übergibt die ID-Nummer an die Funktion edit() über das Argument id. Sie fügen diesen Wert der Funktion get_post() hinzu, um den Beitrag, der mit der bereitgestellten ID verknüpft ist, aus der Datenbank abzurufen. Die neuen Daten kommen in einer POST-Anfrage, die in der Bedingung if request.method == 'POST' verwaltet wird.

Genau wie bei der Erstellung eines neuen Beitrags extrahieren Sie die Daten zuerst aus dem request.form-Objekt und flashen dann eine Nachricht, wenn der Titel einen leeren Wert hat; andernfalls öffnen Sie eine Datenbankverbindung. Dann aktualisieren Sie die Tabelle posts durch Festlegen eines neuen Titels und eines neuen Inhalts, wobei die ID des Beitrags in der Datenbank gleich der ID ist, die in der URL enthalten war.

Im Fall einer GET-Anfrage rendern Sie eine Vorlage edit.html, indem Sie die Variable post übergeben, die den zurückgegebenen Wert der Funktion get_post() enthält. Sie tun das, um den bestehenden Titel und Inhalt auf der Bearbeitungsseite anzuzeigen.

Speichern und schließen Sie die Datei und erstellen Sie dann eine neue edit.html-Vorlage:

  • nano templates/edit.html

Schreiben Sie in dieser neuen Datei den folgenden Code:

flask_blog/templates/edit.html
{% extends 'base.html' %}

{% block content %}
<h1>{% block title %} Edit "{{ post['title'] }}" {% endblock %}</h1>

<form method="post">
    <div class="form-group">
        <label for="title">Title</label>
        <input type="text" name="title" placeholder="Post title"
               class="form-control"
               value="{{ request.form['title'] or post['title'] }}">
        </input>
    </div>

    <div class="form-group">
        <label for="content">Content</label>
        <textarea name="content" placeholder="Post content"
                  class="form-control">{{ request.form['content'] or post['content'] }}</textarea>
    </div>
    <div class="form-group">
        <button type="submit" class="btn btn-primary">Submit</button>
    </div>
</form>
<hr>
{% endblock %}

Speichern und schließen Sie die Datei.

Dieser Code folgt dem gleichen Muster, außer der Syntax {{ request.form['title'] or post['title'] }} und {{ request.form['content'] or post['content'] }}. Das zeigt die in der Anfrage gespeicherten Daten an, so vorhanden. Andernfalls werden die Daten aus der Variablen post angezeigt, die mit den aktuellen Datenbankdaten an die Vorlage übergeben wurde.

Navigieren Sie nun zur folgenden URL, um den ersten Beitrag zu bearbeiten:

http://127.0.0.1:5000/1/edit

Sie werden eine Seite Edit “First Post” sehen.

Seite zum Bearbeiten eines Beitrags

Bearbeiten Sie den Beitrag und übermitteln Sie das Formular; überprüfen Sie dann, ob der Beitrag aktualisiert wurde.

Nun müssen Sie für jeden Beitrag auf der Indexseite einen Link hinzufügen, der auf die Bearbeitungsseite verweist. Öffnen Sie die Vorlagendatei index.html:

  • nano templates/index.html

Bearbeiten Sie die Datei, damit sie genau wie folgt aussieht:

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

{% block content %}
    <h1>{% block title %} Welcome to FlaskBlog {% endblock %}</h1>
    {% for post in posts %}
        <a href="{{ url_for('post', post_id=post['id']) }}">
            <h2>{{ post['title'] }}</h2>
        </a>
        <span class="badge badge-primary">{{ post['created'] }}</span>
        <a href="{{ url_for('edit', id=post['id']) }}">
            <span class="badge badge-warning">Edit</span>
        </a>
        <hr>
    {% endfor %}
{% endblock %}

Speichern und schließen Sie die Datei.

Hier fügen Sie ein <a>-Tag hinzu, um eine Verknüpfung zur Ansichtsfunktion edit() herzustellen. Dazu übergeben Sie den Wert post['id'], um mit dem Link Edit eine Verknüpfung zur Bearbeitungsseite der einzelnen Beiträge herzustellen.

Löschen eines Beitrags

Manchmal müssen Beiträge nicht mehr öffentlich verfügbar sein. Dafür gibt es die Funktion zum Löschen von Beiträgen. In diesem Schritt fügen Sie Ihrer Anwendung die Löschfunktion hinzu.

Zuerst fügen Sie eine neue Route /ID/delete hinzu, die POST-Anfragen akzeptiert, ähnlich wie bei der Ansichtsfunktion edit(). Ihre neue delete()-Ansichtsfunktion empfängt die ID des Beitrags, der gelöscht werden soll, aus der URL. Öffnen Sie die Datei app.py:

  • nano app.py

Fügen Sie am Ende der Datei die folgende Ansichtsfunktion hinzu:

flask_blog/app.py
# ....

@app.route('/<int:id>/delete', methods=('POST',))
def delete(id):
    post = get_post(id)
    conn = get_db_connection()
    conn.execute('DELETE FROM posts WHERE id = ?', (id,))
    conn.commit()
    conn.close()
    flash('"{}" was successfully deleted!'.format(post['title']))
    return redirect(url_for('index'))

Diese Ansichtsfunktion akzeptiert nur POST-Anfragen. Das bedeutet, dass, wenn Sie in Ihrem Browser zur Route /ID/delete navigieren, ein Fehler zurückgegeben wird, da Webbrowser standardmäßig GET-Anfragen nutzen.

Sie können diese Route jedoch über ein Formular aufrufen, das eine POST-Anfrage sendet, mit der die ID des Beitrags übergeben wird, den Sie löschen möchten. Die Funktion empfängt den ID-Wert und verwendet ihn, um den Beitrag mit der Funktion get_post() aus der Datenbank abzurufen.

Dann öffnen Sie eine Datenbankverbindung und führen einen DELETE FROM-SQL-Befehl aus, um den Beitrag zu löschen. Sie übergeben die Änderung an die Datenbank und schließen die Verbindung, während Sie dem Benutzer eine Nachricht flashen, dass der Beitrag erfolgreich gelöscht wurde, und leiten ihn zur Indexseite weiter.

Beachten Sie, dass Sie eine Vorlagendatei nicht rendern, da Sie der Bearbeitungsseite einfach eine Delete-Schaltfläche hinzufügen.

Öffnen Sie die Vorlagendatei edit.html:

  • nano templates/edit.html

Fügen Sie dann das folgende <form>-Tag nach dem Tag <hr> und direkt vor der Zeile {% endblock %} hinzu:

flask_blog/templates/edit.html
<hr>

<form action="{{ url_for('delete', id=post['id']) }}" method="POST">
    <input type="submit" value="Delete Post"
            class="btn btn-danger btn-sm"
            onclick="return confirm('Are you sure you want to delete this post?')">
</form>

{% endblock %}

Sie verwenden die Methode confirm(), um eine Bestätigungsmeldung anzuzeigen, bevor die Anfrage übermittelt wird.

Navigieren Sie nun erneut zur Bearbeitungsseite eines Blogbeitrags und versuchen Sie, ihn zu löschen:

http://127.0.0.1:5000/1/edit

Am Ende dieses Schritts sieht der Quellcode Ihres Projekts wie der Code auf dieser Seite aus.

Damit können die Benutzer Ihrer Anwendung nun neue Blogbeiträge schreiben und der Datenbank hinzufügen sowie bestehende Beiträge bearbeiten und löschen.

Zusammenfassung

Dieses Tutorial hat eine Einleitung in grundlegende Konzepte des Flask-Python-Frameworks geboten. Sie haben gelernt, wie Sie eine kleine Webanwendung erstellen und auf einem Entwicklungsserver ausführen sowie dem Benutzer erlauben, über URL-Parameter und Webformulare benutzerdefinierte Daten anzugeben. Außerdem haben Sie die Jinja-Vorlagen-Engine verwendet, um HTML-Dateien wiederzuverwenden und Logik darin zu nutzen. Am Ende dieses Tutorials verfügen Sie nun über einen voll funktierende Weblog, der mit einer SQLite-Datenbank interagiert, um mithilfe der Python-Sprache und SQL-Abfragen das Erstellen, Anzeigen, Bearbeiten und Löschen von Blogbeiträgen zu ermöglichen.

Sie können diese Anwendung weiter entwickeln, indem Sie Benutzerauthentifizierung hinzufügen, damit nur registrierte Benutzer Blogbeiträge erstellen und ändern können. Außerdem können Sie zu jedem Blogbeitrag Kommentare und Tags sowie Datei-Upload-Funktionen hinzufügen, damit Benutzer die Möglichkeit haben, Bilder im Beitrag zu verwenden. Weitere Informationen finden Sie in der Flask-Dokumentation.

Flask verfügt über eine Vielzahl von Flask-Erweiterungen, die von der Community entwickelt wurden. Im Folgenden finden Sie eine Liste von Erweiterungen, die Sie verwenden können, um Ihren Entwicklungsprozess zu erleichtern:

  • Flask-Login: verwaltet die Benutzersitzung und übernimmt die An- und Abmeldung sowie das Erinnern angemeldeter Benutzer.
  • Flask-SQLAlchemy: vereinfacht die Verwendung von Flask mit SQLAlchemy, einem Python-SQL-Toolkit, und Object Relational Mapper zur Interaktion mit SQL-Datenbanken.
  • Flask-Mail: hilft beim Versand von E-Mail-Nachrichten in Ihrer Flask-Anwendung.
Creative Commons License