13. Unterrichtsblock

Kursinhalte

  • Was ist Flask?
  • Installation von Flask
  • Bedeutung von JSON für Flask

Einführung in Flask

Was ist Flask?

Flask ist ein leichtgewichtiges Python-Framework für Webanwendungen mit grundlegender Unterstützung für URL-Routing und Seitenrendering. Es gehört zur Kategorie der sogenannten Mikro-Frameworks, da es bewusst auf integrierte Funktionen wie Validierung, Datenbankabstraktion oder Authentifizierung verzichtet. Stattdessen können solche Features bei Bedarf über Flask-Erweiterungen eingebunden werden – spezielle Python-Pakete, die gezielt einzelne Funktionalitäten ergänzen.

Obwohl Flask keine eigene Template-Engine mitbringt, ist bei der Installation standardmäßig die Jinja-Vorlagenengine enthalten. Diese ermöglicht es, HTML-Seiten dynamisch zu generieren und mit Python-Daten zu verknüpfen – ein zentraler Bestandteil moderner Webentwicklung.

Warum Flask?

Flask ist besonders beliebt in der Ausbildung und bei Projekten, die schnell und flexibel umgesetzt werden sollen. Es eignet sich hervorragend für:

  • den Einstieg in Webentwicklung mit Python,
  • das Erstellen von Prototypen,
  • die Integration von Machine-Learning-Modellen in Weboberflächen,
  • REST-APIs und datengetriebene Anwendungen.

Was kann Flask?

Mit Flask kannst du:

  • HTTP-Routen definieren (z. B. /start, /kontakt, /api),
  • HTML-Seiten anzeigen (z. B. mit Jinja2-Templates),
  • Formulare verarbeiten und Daten empfangen,
  • JSON-Daten senden und empfangen (z. B. für KI-Modelle),
  • Sessions und Cookies verwalten,
  • externe Bibliotheken wie Bootstrap oder JavaScript einbinden.

Grundprinzip

Flask basiert auf einem einfachen Prinzip: Du definierst Funktionen in Python und verknüpfst sie mit bestimmten URLs. Wenn ein Benutzer eine URL aufruft, wird die zugehörige Funktion ausgeführt und liefert eine Antwort – z. B. eine HTML-Seite oder ein Ergebnis aus einem Modell.

Beispiel:

@app.route('/')
def home():
    return 'Willkommen bei Flask!'

Technischer Hintergrund

  • Flask wurde 2010 von Armin Ronacher entwickelt.
  • Es basiert auf Werkzeug (für HTTP) und Jinja2 (für Templates).
  • Es ist modular erweiterbar: Du kannst bei Bedarf Datenbanken, Authentifizierung oder Admin-Interfaces hinzufügen.

Begleitendes Video-Tutorial für diesen Block

Zur praktischen Vertiefung und als visuelle Anleitung werden wir in diesem Unterrichtsblock mehrfach auf das folgende Video zurückgreifen:

FLASK Python Tutorial für Anfänger – WebApps erstellen in 60 Minuten

Weiteres Flask Tutorial: https://code.visualstudio.com/docs/python/tutorial-flask

Installation von Flask in VS Code

Aufgabe:

Schaue dir das oben genannte Video bis Minute 14 an und fahre dann mit der Installation von Flask fort.

Wichtig!

Bevor wir mit Flask arbeiten können, müssen wir sicherstellen, dass unser Python-Interpreter korrekt eingerichtet ist und dass wir eine virtuelle Umgebung nutzen. Dies verhindert, dass Flask global installiert wird, und gibt uns die volle Kontrolle über die Bibliotheken, die in einem Projekt verwendet werden.

Schritt-für-Schritt-Anleitung

1. Python-Interpreter prüfen

  • Öffne die Eingabeaufforderung (CMD) oder PowerShell.
  • Gib ein:bashpython --version
  • Wenn der Befehl nicht funktioniert, muss der Speicherort des Python-Interpreters in der PATH-Umgebungsvariablen eingetragen werden.
    • Beispiel: C:\Users\<Name>\AppData\Local\Programs\Python\Python311\
    • Danach erneut testen.

2. Projektordner erstellen

  • Lege einen neuen Ordner für dein Projekt an, z. B. flask_app.
  • Öffne diesen Ordner in Visual Studio Code.

3. Virtuelle Umgebung erstellen (wichtig!) Im VS Code-Terminal:

python -m venv venv
  • Dadurch wird ein Unterordner venv erstellt, der alle Projektabhängigkeiten isoliert.
  • Vorteil: Flask wird nur für dieses Projekt installiert und nicht global.

4. Virtuelle Umgebung aktivieren

  • Windows (PowerShell):bashvenv\Scripts\activate
  • Nach der Aktivierung erscheint (venv) vor der Eingabezeile im Terminal.

5. Flask installieren Mit aktivierter virtueller Umgebung:

pip install flask

6. Installation überprüfen

python -m flask --version

Du solltest eine Ausgabe wie Flask 3.x.x sehen.

7. Erste Test-App erstellen Lege im Projektordner eine Datei app.py an:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def home():
    return 'Hello Flask!'

if __name__ == '__main__':
    app.run(debug=True)

8. App starten Im Terminal:

python app.py

9. Ergebnis prüfen Öffne im Browser:

http://127.0.0.1:5000/

Du solltest die Ausgabe „Hello Flask!“ sehen.


⚠️ Hinweis

  • Die Verwendung einer virtuellen Umgebung ist entscheidend:
  • Sie erleichtert die Wartung und vermeidet Versionskonflikte.
  • Sie verhindert, dass Flask in der globalen Python-Umgebung installiert wird.
  • Sie sorgt dafür, dass jede Anwendung ihre eigenen Bibliotheken hat.

Aufgabe: Dynamisches Routing testen

Ziel

Stelle sicher, dass Flask nicht nur statische Seiten, sondern auch dynamische Routen verarbeiten kann, indem du eine Variable direkt aus der URL ausliest.

Schritte zur Ausführung

1. Code anpassen und zwei Routen definieren

  • Öffne die Datei app.py und ersetze den Code durch die folgende erweiterte Version. Diese Version definiert zwei Routen:
    1. Die Startseite (/)Eine dynamische Route (/gruss/<name>), die einen Teil der URL als Variable entgegennimmt.
    Pythonfrom flask import Flask # Erstellt eine Instanz der Flask-Anwendung app = Flask(__name__) # 1. Statische Route (Startseite) @app.route('/') def index(): return 'Willkommen auf der Startseite. Versuche /gruss/DeinName' # 2. Dynamische Route mit Variable @app.route('/gruss/<name>') def personalisierter_gruss(name): # Die Variable 'name' wird automatisch aus der URL entnommen return f'Hallo, {name}! Deine Flask-Installation funktioniert mit dynamischen URLs.' if __name__ == '__main__': app.run(debug=True)

2. Anwendung neu starten

  • Beende die laufende Flask-Anwendung im Terminal mit CTRL + C.
  • Starte die Anwendung neu:Bashpython app.py

3. Testen der dynamischen Route

  • Öffne den Webbrowser.
  • Test 1 (Statische Route): Navigiere zur Startseite: http://127.0.0.1:5000/
  • Test 2 (Dynamische Route): Geben deinen Namen oder einen beliebigen Text in die URL ein: http://127.0.0.1:5000/gruss/Max (Ersetze „Max“ durch deinen Namen)

Erfolgsnachweis

  • Die Aufgabe ist erfolgreich abgeschlossen, wenn nach Aufruf von /gruss/Max im Browser der Text „Hallo, …! Deine Flask-Installation funktioniert mit dynamischen URLs.“ angezeigt wird.

Dies bestätigt, dass alle Kernkomponenten (virtuelle Umgebung, Flask, Routing) einsatzbereit sind.

JSON: Das Standard-Datenformat für Web-APIs

Flask wird in der modernen Webentwicklung primär dazu eingesetzt, Web-APIs (Schnittstellen) zu bauen. Diese APIs dienen dazu, strukturierte Daten mit anderen Programmen (wie JavaScript-Frontends, mobilen Apps oder anderen Servern) auszutauschen.

Die universelle Sprache für diesen Datenaustausch im Web ist JSON (JavaScript Object Notation).

Um von Anfang an funktionale Backend-Anwendungen erstellen zu können, führen wir daher zunächst den Abschnitt zur JSON-Analyse und -Erstellung ein. Dieses Wissen ist die Grundlage dafür, dass unsere Flask-Routen später nicht nur einfachen Text, sondern sinnvolle, strukturierte Daten verarbeiten und zurückgeben können.

1. Daten empfangen (Vom Client zum Flask-Server)

Wenn ein Webbrowser, eine mobile App oder ein anderes Programm Daten an Ihren Flask-Server sendet (z. B. wenn sich ein Benutzer registriert oder eine Bestellung aufgibt), werden diese Daten in der Regel als JSON-Payload gesendet.

  • Flask bietet eine spezielle Methode, um diese eingehenden JSON-Daten direkt zu verarbeiten: request.get_json() (oder das Attribut request.json).
  • Diese Methode übernimmt die Arbeit des Python-internen json-Moduls für Sie und konvertiert die JSON-Daten automatisch in ein Python-Dictionary (Wörterbuch), mit dem Sie dann in Ihrem Code einfach arbeiten können.
    • Ohne diese Konvertierung wären die Daten nur ein unverarbeiteter Text-String.

2. Daten senden (Vom Flask-Server zum Client)

Wenn Ihr Flask-Server eine Antwort an den Client schickt (z. B. eine Liste von Produkten), müssen Sie Ihre Python-Datenstrukturen (Dictionaries oder Listen) wieder in das JSON-Format umwandeln, damit der Client sie verstehen kann.

  • In Flask können Sie oft einfach ein Python-Dictionary aus Ihrer View-Funktion zurückgeben, und Flask kümmert sich automatisch um die Serialisierung (Umwandlung) in JSON.

Zusammenfassend: JSON ist die Sprache der Web-APIs. Um mit Flask als API-Backend effektiv arbeiten zu können, müssen Sie wissen, wie diese JSON-Daten empfangen und in native Python-Datenstrukturen (wie z. B. Dictionaries und Listen) umgewandelt werden. Daher ist die JSON-Analyse ein unverzichtbarer Bestandteil des gesamten Themas „Flask und Webentwicklung“.

Aufgabe: API-Endpunkt für Produktinformationen

Ziel: Du erstellst einen einfachen API-Endpunkt (/produkt), der eine Anfrage im JSON-Format annimmt, die Daten verarbeitet (spezielles Feld herausliest) und eine formatierte JSON-Antwort zurückgibt.

Vorbereitung (Setup)

  • Erstelle die Datei api_app.py in deinem Projektordner.
  • Importiere die notwendigen Flask-Module (Flask, request und jsonify).

Schritte zur Implementierung

1. API-Route definieren

  • Definiere eine Route namens /produkt.
  • Stelle sicher, dass diese Route sowohl die Methoden GET (für das Senden von JSON) als auch POST (für das Empfangen von JSON) erlaubt.

2. Daten empfangen (POST-Anfrage)

  • Implementiere eine Logik in der Route, die prüft, ob die Anfrage per POST-Methode gesendet wurde.
  • Lese die eingehende JSON-Nutzlast (Payload) über request.get_json() in eine Variable (z. B. daten) ein.
  • Prüfe: Ob der Schlüssel produktname in den empfangenen daten vorhanden ist.

3. Daten verarbeiten und antworten

  • Wenn der produktname vorhanden ist, erstelle ein Python-Dictionary als Antwort, das folgende Informationen enthält:
    • status: "erfolg"
    • eingegangen: Der Wert des empfangenen produktname.
    • verarbeitung: "Daten erfolgreich als Dictionary verarbeitet."
  • Gib diese Antwort mithilfe der Funktion jsonify() zurück. (jsonify() konvertiert dein Python-Dictionary automatisch in das korrekte JSON-Antwortformat).

4. Fehlerbehandlung (Optional)

  • Wenn der produktname in der Anfrage fehlt, gib eine Fehlerantwort zurück:
    • status: "fehler"
    • meldung: "Produktname fehlt in der JSON-Payload."

Erwarteter Code-Aufbau (api_app.py)

from flask import Flask, request, jsonify

app = Flask(__name__)

# Erlaubt GET (Standard) und POST (für JSON-Daten)
@app.route('/produkt', methods=['GET', 'POST'])
def produkt_api():
    # Dein Code hier
    # ...
    pass

if __name__ == '__main__':
    app.run(debug=True)

Test der Anwendung

Da ein Browser keine POST-Anfrage mit JSON-Payload senden kann, musst du die Funktionalität mit einem Tool testen (z. B. Postman, VS Code-Erweiterungen wie REST Client, oder dem Python-Modul requests in einem neuen Skript).

  1. Starte die Anwendung: python api_app.py
  2. Sende eine POST-Anfrage an http://127.0.0.1:5000/produkt mit folgendem JSON-Body:
{
  "produktname": "Webcam Pro X5",
  "preis": 89.99
}

Erwartete JSON-Antwort:

{
  "eingegangen": "Webcam Pro X5", 
  "status": "erfolg", 
  "verarbeitung": "Daten erfolgreich als Dictionary verarbeitet."
}

Strukturierung des Frontends mit HTML, CSS und Bootstrap

In modernen Webanwendungen spielt das Frontend eine zentrale Rolle: Es ist die Schnittstelle zwischen Nutzer und Anwendung und entscheidet maßgeblich darüber, wie intuitiv und angenehm die Interaktion erlebt wird. Während das Backend die Logik und Datenverarbeitung übernimmt, sorgt das Frontend dafür, dass diese Funktionen visuell zugänglich und verständlich dargestellt werden.

In diesem Abschnitt lernst du, wie du mit den grundlegenden Bausteinen der Webentwicklung – HTML zur Strukturierung von Inhalten und CSS zur Gestaltung des Layouts – eine klare und funktionale Oberfläche aufbaust. Um die Entwicklung effizienter und professioneller zu gestalten, nutzen wir zusätzlich die Bootstrap-Bibliothek, die eine Vielzahl vorgefertigter Komponenten und Design-Elemente bereitstellt. Bootstrap erleichtert es, responsive und ansprechende Oberflächen zu erstellen, die auf unterschiedlichen Geräten und Bildschirmgrößen gleichermaßen gut funktionieren.

Beispiel: Chat UI

Als praktisches Beispiel wirst du eine Chat-Oberfläche entwickeln. Dabei geht es nicht nur um die reine Darstellung von Nachrichten, sondern auch um die sinnvolle Anordnung von Eingabefeldern, Buttons und Ausgaben. Du lernst, wie man mit HTML die Grundstruktur definiert, mit CSS gezielt das Erscheinungsbild anpasst und mit Bootstrap elegante, wiederverwendbare Elemente integriert.

Aufgabe:

Schaue dir nun den Abschnitt: Chat UI mit HTML und CSS (ab ca. 13:58 bis 26:03) an und beantworte folgende Fragen:

Phase 1: Vorbereitung und Flask-Integration

  1. Templates-Ordner: Welchen speziellen Namen muss der Ordner haben, den du in deinem Flask-Projekt anlegst, damit die Anwendung die HTML-Dateien darin findet?
  2. Rückgabe-Funktion: Welche Funktion musst du in deiner Python-Route (@app.route) verwenden, um eine HTML-Datei anzuzeigen, anstatt nur einen einfachen Text-String zurückzugeben?

Phase 2: Externe Bibliotheken und Grundstruktur

  1. Bootstrap-Zweck: Welchen primären Vorteil bietet dir das CSS-Framework Bootstrap bei der Erstellung der Chat-Oberfläche im Vergleich zur reinen Nutzung von eigenem CSS?
  2. Einbindung: An welcher Stelle in der index.html-Datei bindest du die CSS-Links von Bootstrap ein (im <head> oder im <body>) und warum gerade dort?

Phase 3: Nachrichten-Layout und Ausrichtung

  1. Nachrichten-Trennwand: Welche Bootstrap-Klasse nutzt der Dozent, um die eigenen Chat-Nachrichten an das rechte Ende des Containers zu verschieben?
  2. CSS-Abstand: Mit welcher Bootstrap-Klasse kannst du einen vertikalen Abstand zwischen den einzelnen Nachrichten-Karten erzeugen (z. B. 3 Einheiten Abstand nach oben)?

Phase 4: Fixierte Eingabeleiste

  1. Datenversand: Welches HTML-Element verwendest du, um das Eingabefeld und den Senden-Button zu gruppieren, damit die darin enthaltenen Daten beim Klick auf den Button an den Flask-Server gesendet werden können?
  2. Fixierung: Welche kritische CSS-Eigenschaft (keine Bootstrap-Klasse, sondern reines CSS) nutzt der Dozent, um die Eingabeleiste fest am unteren Rand des Browserfensters zu verankern?
  3. Breiten-Berechnung: Da die Eingabeleiste fixiert wird, muss ihre Breite manuell angepasst werden. Welche CSS-Funktion ermöglicht es, die volle Breite (100%) zu nutzen, aber gleichzeitig den Randabstand (160px) abzuziehen?

Vertiefung der Konzepte: Wie das Frontend funktioniert

1. Die Flask-Templating-Architektur

Bevor du HTML-Code schreiben kannst, muss Python wissen, wo diese Dateien liegen und wie es sie anzeigt.

  • Der templates-Ordner: In Flask muss du alle deine HTML-Dateien (Templates) in einem Unterordner mit dem exakten Namen templates ablegen. Dies ist eine feste Konvention des Flask-Frameworks. Legst du die Dateien woanders ab, findet Flask sie nicht.
  • Die Funktion render_template: Wenn eine deiner Routen (z. B. @app.route('/')) eine HTML-Seite ausgeben soll, verwendest du nicht return '<h1>...</h1>', sondern:
return render_template('index.html')

Diese Funktion weist Flask an, die angeforderte Datei aus dem speziellen Ordner zu laden und an den Browser zu senden.

2. Layout-Steuerung mit Flexbox (Bootstrap)

Um die Chat-Nachrichten korrekt auszurichten (eigene Nachrichten rechts, fremde Nachrichten links), nutzt du die Leistungsfähigkeit des CSS-Konzepts Flexbox, welches von Bootstrap vereinfacht wird.

  • d-flex (Display Flex): Du wendest diese Bootstrap-Klasse auf den Container an, der die Nachricht umgibt. Dadurch wird dieser Container zu einem Flex-Container, dessen Inhalt nun flexibel gesteuert werden kann.
  • justify-content: Diese Eigenschaft steuert die horizontale Verteilung des Inhalts innerhalb des Flex-Containers.
    • justify-content-end: Platziert die Nachricht am rechten Ende des Containers (perfekt für die eigene Nachricht).
    • justify-content-start: Platziert die Nachricht am linken Ende des Containers (für alle fremden Nachrichten).
  • Modularität: Durch die Nutzung von Bootstrap-Klassen wie card (für den Nachrichten-Hintergrund) und mt-3 (für den vertikalen Abstand) erstellst du eine saubere, mobile-freundliche Oberfläche, ohne Hunderte Zeilen eigenen CSS-Code schreiben zu müssen.

3. Das fixierte Formular: Positionierung mit reinem CSS

Die Eingabeleiste am unteren Bildschirmrand muss immer sichtbar bleiben, auch wenn du scrollst. Dies erfordert das Arbeiten mit klassischem CSS.

  • position: fixed: Dies ist die entscheidende CSS-Eigenschaft. Sie bewirkt, dass das Element aus dem normalen Dokumentenfluss entfernt wird und seine Position relativ zum Browserfenster beibehält. Egal, wie weit der Benutzer scrollt, das Element bleibt fixiert.
  • Die calc()-Funktion: Da das fixierte Element keine automatischen Container-Ränder erbt, musst du seine Breite manuell anpassen, um es von Rand zu Rand mit korrektem Abstand darzustellen:
width: calc(100% - 160px);

Die Funktion calc() erlaubt es dir, die volle verfügbare Breite (100%) zu nehmen und davon den benötigten Gesamt-Randabstand (z. B. 80px links + 80px rechts = 160px) abzuziehen.

Aufgabe: Aufbau der Chat-UI

Ziel: Du erstellst die visuelle Struktur des Chat-Messengers (index.html), bindest das Styling-Framework Bootstrap ein und positionierst das Eingabefeld fixiert am unteren Bildschirmrand.

1. Flask-Templates vorbereiten

Du musst die HTML-Datei im korrekten Ordner ablegen, damit Flask sie anzeigen kann.

  1. Erstelle in deinem Hauptprojektordner den Unterordner templates.
  2. Erstelle in diesem Ordner die Datei index.html.
  3. Passe deine Python-Anwendung (app.py oder api_app.py) so an, dass sie die neue Datei rendert. Importiere dazu render_template und nutze es in deiner Haupt-Route (@app.route('/')).

2. HTML-Gerüst und Bootstrap einbinden

Du legst die Basisstruktur fest und bindest Bootstrap für das schnelle Design ein.

  1. Erstelle in index.html das standardmäßige HTML5-Grundgerüst.
  2. Binde die Bootstrap CSS-Links in den <head>-Bereich deiner HTML-Datei ein.
  3. Füge den Haupt-Container für den Inhalt (eine div mit der Klasse container) in den <body>-Bereich ein.

3. Nachrichten-Darstellung simulieren

Du erstellst die visuelle Struktur für zwei Nachrichten – eine links und eine rechts ausgerichtet.

  1. Füge zwei separate Nachrichten-Blöcke (Karten oder ähnliche div-Strukturen) in deinen Haupt-Container ein.
  2. Richte die erste Nachricht links aus (simuliert eine fremde Nachricht).
  3. Richte die zweite Nachricht rechts aus (simuliert deine eigene Nachricht) mit der dafür notwendigen Flexbox-Klasse.
  4. Verwende die Bootstrap-Klassen (mt-3, card etc.), um beiden Nachrichten eine optische Struktur und Abstand zu geben.

4. Das fixierte Eingabe-Formular

Das Formular muss immer am unteren Rand haften bleiben, damit der Benutzer jederzeit eine Nachricht senden kann.

  1. Erstelle ein <form>-Element und gib ihm die Methode POST (auch wenn wir die Daten noch nicht verarbeiten).
  2. Füge in dieses Formular das Text-Eingabefeld (<input>) und den Senden-Button ein.
  3. Erstelle im <head>-Bereich einen <style>-Block für dein eigenes CSS.
  4. Definiere in diesem <style>-Block eine CSS-Klasse für das Formular, die:
    • Die Eigenschaft position: fixed setzt.
    • Die bottom– und left-Eigenschaften für die Positionierung setzt.
    • Die Breite unter Verwendung der calc()-Funktion berechnet, um die Breite des Fensters abzudecken und gleichzeitig Platz für die Ränder zu lassen.

Erfolgsnachweis

  • Der Server läuft: Deine Flask-Anwendung (app.py oder api_app.py) ist aktiv und die virtuelle Umgebung ist aktiviert.
  • Optisches Ergebnis: Wenn du die URL im Browser öffnest, siehst du eine Chat-Oberfläche mit:
    • Einem Header.
    • Mindestens zwei gestylten Nachrichten (eine links, eine rechts).
    • Einem fixiert am unteren Rand positionierten Eingabefeld, das beim Scrollen an seiner Stelle bleibt.

Datenbank-Einrichtung und -Modellierung

Ein wesentliches Merkmal moderner Webanwendungen ist die Fähigkeit, Daten nicht nur kurzfristig zu verarbeiten, sondern sie auch dauerhaft zu speichern. Während einfache Flask-Apps zunächst nur auf flüchtige Informationen reagieren – etwa Eingaben, die direkt im Speicher verarbeitet und anschließend wieder verworfen werden – entsteht echter Mehrwert erst dann, wenn Inhalte wie Nachrichten, Benutzerinformationen oder Einstellungen auch nach einem Neustart der Anwendung verfügbar bleiben.

Dieser Block widmet sich genau dieser Frage: Wie kann deine Flask-Anwendung Nachrichten persistent speichern? Die Lösung liegt in der Anbindung einer Datenbank. Mithilfe einer Datenbank-Erweiterung für Flask, wie beispielsweise Flask-SQLAlchemy, lassen sich Daten strukturiert ablegen, verwalten und jederzeit wieder abrufen.

Warum Persistenz wichtig ist

  • Nachhaltigkeit: Nachrichten oder andere Inhalte bleiben auch nach dem Schließen der Anwendung erhalten.
  • Struktur: Daten werden in Tabellen organisiert und können effizient durchsucht und gefiltert werden.
  • Skalierbarkeit: Mit einer Datenbank kann deine Anwendung wachsen und große Datenmengen verarbeiten.
  • Praxisnähe: Persistenz ist ein Standard in professionellen Anwendungen – von Chat-Apps bis hin zu komplexen Plattformen.

1. Das Bedürfnis nach Persistenz

Bisher existiert der Chat nur so lange, wie die Flask-Anwendung läuft. Startest du den Server neu, wären alle Nachrichten verloren.

  • Lösung: Um Daten dauerhaft zu speichern und abrufbar zu machen, benötigst du eine Datenbank.
  • Datenbank-Typ: Im Video wird SQLite verwendet. Dies ist eine einfache, dateibasierte Datenbank (die gesamte Datenbank liegt in einer einzigen .db-Datei) und ist ideal für kleine Projekte und den Einstieg.

2. Flask-SQLAlchemy (Der Datenbank-Konnektor)

Flask selbst hat keine integrierte Datenbankunterstützung. Du bindest diese Funktionalität über eine spezielle Flask-Erweiterung ein:

  • Name: Flask-SQLAlchemy.
  • Funktion: Diese Erweiterung ist ein sogenannter Object-Relational Mapper (ORM). Ein ORM dient als Übersetzer: Er erlaubt dir, mit Python-Objekten (Klassen) zu arbeiten, anstatt komplizierte SQL-Befehle schreiben zu müssen. Das macht die Datenbank-Interaktion für Python-Entwickler einfacher und sicherer.
  • Installation: Die Installation erfolgt über den Paketmanager (pip install flask-sqlalchemy).

3. Konfiguration der Datenbank-Verbindung

Bevor du die Datenbank nutzen kannst, musst du Flask mitteilen, wo die Datenbank-Datei liegt:

  • App-Konfiguration: Dies geschieht über das app.config-Dictionary in deiner Python-Anwendung.
  • Der Verbindungsparameter (SQLALCHEMY_DATABASE_URI):Pythonapp.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.db' Dieser String definiert den Pfad zur Datenbank. sqlite:/// teilt SQLAlchemy mit, dass es sich um eine SQLite-Datenbank handelt, und db.db gibt an, dass die Datei im Hauptordner des Projekts liegen soll.
  • Initialisierung: Anschließend wird die Erweiterung mit der App-Instanz verknüpft: db = SQLAlchemy(app).

4. Datenmodellierung mit Klassen (ORM)

Der wichtigste Schritt ist die Definition des Datenmodells. Du nutzt das in früheren Blöcken erlernte Wissen über Klassen und die Objektorientierte Programmierung (OOP), um eine Tabelle in der Datenbank abzubilden.

  • Klasse = Tabelle: Jede Python-Klasse, die von db.Model erbt, wird zu einer Tabelle in der Datenbank.
    • Beispiel: Eine Klasse Message(db.Model) wird zur Datenbanktabelle message.
  • Attribute = Spalten: Die Attribute (Eigenschaften), die du in der Klasse definierst, werden zu den Spalten der Tabelle.

Aufbau der Spalten (db.Column):

Jede Spalte benötigt einen Typ und bestimmte Parameter:

ParameterBeispielErklärung
Primärschlüsseldb.Column(db.Integer, primary_key=True)Eine eindeutige ID für jede Zeile. Muss für die Tabelle definiert werden und wird automatisch hochgezählt.
Datentypdb.Column(db.String(200))Definiert, welche Art von Daten gespeichert werden (z. B. String für Text, Integer für ganze Zahlen, DateTime für Zeitstempel).
Optionalitätnullable=TrueGibt an, ob das Feld leer sein darf (True) oder unbedingt ausgefüllt werden muss (False).
Standardwertdefault=datetime.datetime.utcnowLegt fest, dass, wenn beim Speichern kein Wert übergeben wird, ein Standardwert verwendet wird (hier: das aktuelle Datum und die Uhrzeit).

5. Erstellung der Datenbank-Datei (db.create_all())

Nachdem das Datenmodell (die Klasse) definiert wurde, erstellst du die Datenbank physisch:

  • Befehl: Du führst den Befehl db.create_all() einmalig aus.
  • Funktion: Dieser Befehl liest alle deine db.Model-Klassen und erstellt die entsprechenden Tabellen in der db.db-Datei.

Anschließend ist deine Anwendung bereit, um Daten mit diesem Modell zu speichern und abzurufen.

Aufgabe: Datenbank-Modellierung mit Flask-SQLAlchemy

Ziel: Du installierst die notwendige ORM-Erweiterung (Flask-SQLAlchemy), konfigurierst die Datenbankverbindung und definierst das Python-Klassenmodell für deine message-Tabelle.

Schaue dir den Abschnitt: Datenbank-Einrichtung und -Modellierung (von ca. 26:03 bis 35:15) an und setze die folgenden Schritte um.


1. Installation und Konfiguration

Du beginnst mit der Installation der Erweiterung und legst die Verbindung zur Datenbank-Datei fest.

  1. Erweiterung installieren:
    • Stelle sicher, dass deine virtuelle Umgebung ((venv)) aktiviert ist.
    • Installiere die notwendige Flask-Erweiterung, die als ORM dient:Bashpip install flask-sqlalchemy
  2. Imports vorbereiten:
    • Öffne deine Haupt-Python-Datei (z. B. app.py).
    • Importiere die benötigten Module für Datenbank und Datum:Pythonfrom flask_sqlalchemy import SQLAlchemy from datetime import datetime
  3. Konfiguration der Verbindung:
    • Füge nach der Initialisierung deiner Flask-App (app = Flask(__name__)) die folgenden Konfigurationszeilen ein, um Flask mitzuteilen, dass du eine SQLite-Datenbank (db.db) nutzen möchtest:Python# Konfiguration der Datenbank-URI (SQLite-Datei im Hauptverzeichnis) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.db' # Deaktiviert unnötige Warnungen app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Initialisierung der SQLAlchemy-Erweiterung db = SQLAlchemy(app)

2. Datenmodell definieren (Die Message-Klasse)

Du definierst nun die Python-Klasse, die die Struktur deiner message-Tabelle in der Datenbank abbildet.

  1. Erstelle die Klasse:
    • Definiere eine Klasse namens Message, die von db.Model erbt:Pythonclass Message(db.Model): # ... Spaltendefinitionen folgen hier ... pass
  2. Spalten definieren:
    • Füge die folgenden Spalten-Attribute in deine Message-Klasse ein:
      • id: Definiere dies als db.Integer und setze es als primary_key=True, damit jede Nachricht eine eindeutige, automatisch generierte Nummer erhält.
      • user: Ein Textfeld (db.String) für den Nutzernamen (z. B. max. 200 Zeichen).
      • content: Ein längeres Textfeld (db.String) für den eigentlichen Nachrichtentext.
      • created_at: Ein Datumsfeld (db.DateTime) für den Zeitstempel. Setze hier den default-Wert auf datetime.utcnow, damit das aktuelle Datum und die Uhrzeit beim Speichern automatisch hinzugefügt werden.

3. Datenbank physisch erstellen

Nachdem das Modell definiert wurde, musst du die Datenbank-Datei im Dateisystem erzeugen.

  1. Starte den Python-Interpreter:
    • Beende deine Flask-App (CTRL + C).
    • Starte den interaktiven Python-Interpreter im Terminal:Bashpython
  2. Tabellen erstellen:
    • Importiere das db-Objekt und führe den Erstellungsbefehl aus:Pythonfrom app import app, db # Erstellt die Datenbank-Datei (db.db) und die Tabelle 'message' with app.app_context(): db.create_all()
    • Verlasse den Interpreter mit exit().

Erfolgsnachweis

  • Du hast eine neue Datei db.db in deinem Projektordner.
  • Wenn du die Datenbank-Datei mit einem SQLite-Viewer öffnest, siehst du eine Tabelle namens message mit den vier definierten Spalten (id, user, content, created_at).

Bist du mit diesen Schritten fertig, ist dein Backend bereit, um Nachrichten dauerhaft zu speichern und abzurufen!

Datenfluss und Speicherung von Nachrichten in Datenbanken

Eine Webanwendung entfaltet ihren vollen Nutzen erst dann, wenn sie nicht nur Eingaben entgegennimmt, sondern diese auch strukturiert verarbeitet und dauerhaft speichert. In diesem Abschnitt lernst du den gesamten Ablauf kennen, den eine Nachricht in deiner Flask-Anwendung durchläuft – von der Eingabe im HTML-Formular über die Verarbeitung im Routing bis hin zur Speicherung im Datenbankmodell (db.db).

Warum ist dieser Weg wichtig?

  • Ganzheitliches Verständnis: Du siehst, wie Frontend und Backend zusammenarbeiten.
  • Praxisnähe: Jede moderne Anwendung – ob Chat, Blog oder Forum – benötigt diesen Ablauf.
  • Verknüpfung von Wissen:

1. Dynamische Routen zur Benutzeridentifikation

Zunächst musst du den Benutzer identifizieren, der die Nachricht sendet. Im Video wird dies einfach über die URL gelöst.

  • Syntax: Die Route wird angepasst, um einen dynamischen Teil zu akzeptieren (z. B. @app.route('/<name>')).
  • Funktionale Übergabe: Der in der URL eingegebene Wert (z. B. „Yunus“) wird automatisch als Parameter an die zugehörige Python-Funktion übergeben:
@app.route('/<name>')
def index(name):  # Der 'name'-Parameter fängt den URL-Wert auf
    # ...
  • Zweck: Dieser Wert wird später verwendet, um die Nachricht in der Datenbank eindeutig dem entsprechenden Benutzer zuzuordnen.

2. HTTP-Methoden: GET und POST

Wenn du das Formular in deinem Frontend absendest, nutzt der Browser die POST-Methode, da du neue Daten an den Server schickst. Deine Flask-Route muss diese Methode explizit erlauben.

  • Die GET-Methode (Standard): Wird verwendet, um Daten abzurufen (z. B. wenn du eine Seite im Browser öffnest oder eine API abfragst).
  • Die POST-Methode (Daten senden): Wird verwendet, um neue Daten an den Server zu senden (z. B. beim Absenden eines Formulars, Registrierung oder Speichern einer Nachricht).
  • Aktivierung: Du erweiterst den Route-Decorator um das Argument methods:Python@app.route('/<name>', methods=['GET', 'POST'])
  • Logik-Trennung: Innerhalb der View-Funktion prüfst du mit der Anweisung if request.method == 'POST':, ob eine Formular-Übermittlung stattgefunden hat. Die gesamte Logik zum Speichern der Daten wird nur in diesem if-Block ausgeführt.

3. Empfangen von Formular-Daten (request.form)

Die Nachricht (der eigentliche Text) wird vom HTML-Formular gesendet und muss vom Backend entgegengenommen werden.

  • Das request-Objekt: Dieses Objekt von Flask enthält alle Informationen zur eingehenden HTTP-Anfrage.
  • request.form: Da die Daten von einem Standard-HTML-Formular gesendet werden (nicht als reines JSON), musst du das Dictionary request.form verwenden. Dieses speichert die übermittelten Schlüssel-Wert-Paare aus dem Formular.
  • Schlüssel-Erkennung: Um auf den eingegebenen Nachrichtentext zuzugreifen, verwendest du den name-Wert des entsprechenden HTML-Input-Feldes (z. B. request.form['content']).

4. Daten speichern mit dem ORM

Nachdem du den Benutzernamen (aus der URL) und den Nachrichtentext (aus dem Formular) hast, verwendest du dein zuvor erstelltes Datenmodell (Message-Klasse), um die Daten zu speichern.

  1. Instanziierung: Du erstellst ein neues Python-Objekt und übergibst die gesammelten Werte:
neue_nachricht = Message(user=name, content=inhalt)

2. Hinzufügen zur Session: Du teilst dem ORM mit, dass dieses neue Objekt zur Datenbank hinzugefügt werden soll:

db.session.add(neue_nachricht)

3. Festschreiben (Commit): Dies ist der entscheidende Schritt. Die commit()-Funktion schreibt die Änderungen dauerhaft in die db.db-Datei:

db.session.commit()

Nach diesem commit ist die Nachricht gespeichert und kann von nun an dauerhaft aus der Datenbank abgerufen werden.

Aufgabe: Speichern der Chat-Nachricht

Ziel: Du erweiterst deine Haupt-Route, um die POST-Methode zu verarbeiten, den Nutzernamen aus der URL und den Nachrichtentext aus dem Formular auszulesen und diese Daten dauerhaft in deiner db.db-Datenbank zu speichern.

Schaue dir den Abschnitt: Datenfluss und Speichern (von ca. 35:29 bis 44:40) an.

1. Route und Methode anpassen

Deine Route muss nun in der Lage sein, den Nutzernamen aus der URL zu erfassen und Formular-Daten über die POST-Methode entgegenzunehmen.

  • Route erweitern: Passe den @app.route-Decorator deiner Haupt-Route in deiner Python-Datei (app.py oder api_app.py) an:
    • Füge den Platzhalter <name> hinzu, um den Benutzernamen aus der URL zu erfassen (z. B. /max).
    • Erlaube explizit die Methode POST.
  • Imports erweitern: Importiere das request-Objekt, das du für die Abfrage der Methode und der Formulardaten benötigst:
from flask import Flask, render_template, request # 'request' hinzufügen
# ... weitere Imports ...
  • Funktions-Signatur: Passe die Funktion, die zur Route gehört, an, damit sie den name-Parameter entgegennimmt:
@app.route('/<name>', methods=['GET', 'POST'])
def index(name):
    # ...

2. Formular-Daten empfangen und speichern

Du implementierst die Logik, die nur bei einer POST-Anfrage ausgeführt wird.

  • POST-Logik einleiten: Starte eine if-Bedingung, um zu prüfen, ob die Anfrage eine Formular-Übermittlung war:Pythonif request.method == 'POST': # Hier kommt die Speicherlogik hin pass
if request.method == 'POST':
    # Hier kommt die Speicherlogik hin
    pass
  • Nachricht auslesen: Innerhalb des if-Blocks liest du den eingegebenen Nachrichtentext aus dem Formular aus. Tipp: Denke daran, den korrekten name-Wert des <input>-Feldes aus deiner index.html zu verwenden, um auf das request.form-Dictionary zuzugreifen.
  • ORM-Objekt erstellen: Erstelle eine neue Instanz deiner Message-Klasse, indem du den name (aus der URL) und den ausgelesenen Nachrichtentext als content übergibst.
  • Datenbank-Operationen: Verwende die db.session-Methoden, um die neue Nachricht zur Datenbank hinzuzufügen und die Änderung festzuschreiben:
    • Füge das erstellte Objekt hinzu (.add()).
    • Bestätige die Transaktion (.commit()).

3. HTML-Formular anpassen

Damit das Formular die Daten korrekt sendet, musst du dein <form>-Tag in der index.html anpassen.

  1. Formular-Methode: Stelle sicher, dass das <form>-Tag die Methode POST verwendet.
  2. Input-Name: Vergewissere dich, dass das <input>-Feld für den Nachrichtentext ein name-Attribut besitzt, damit Flask es über request.form erkennen kann (z. B. <input name="text_input">).

Erfolgsnachweis

  1. Starte deine Flask-Anwendung neu (z. B. unter http://127.0.0.1:5000/DeinName).
  2. Gib im Eingabefeld einen Text ein und klicke auf Senden.
  3. Prüfe mit einem SQLite-Viewer (oder durch die im Video gezeigte Methode), ob eine neue Zeile in der Tabelle message deiner db.db-Datei mit deinem Namen und dem eingegebenen Text hinzugefügt wurde.

Ist die Zeile gespeichert, funktioniert der komplette Datenfluss vom Browser bis zur Datenbank!

Auslesen und Dynamisches Anzeigen

Nachdem du gelernt hast, wie Nachrichten in deiner Flask-Anwendung dauerhaft in der Datenbank gespeichert werden können, folgt nun der nächste entscheidende Schritt: die gespeicherten Daten wieder abrufen und im Browser darstellen. Denn eine Anwendung gewinnt erst dann an praktischer Bedeutung, wenn Nutzer ihre eingegebenen Inhalte auch visuell zurückerhalten und mit ihnen interagieren können.

Hier kommt die Jinja2-Template-Engine ins Spiel, die tief in Flask integriert ist. Jinja2 ermöglicht es dir, HTML-Seiten dynamisch zu gestalten, indem du Daten aus dem Backend direkt in die Oberfläche einbindest. So kannst du beispielsweise eine Liste aller gespeicherten Nachrichten aus der Datenbank abrufen und diese in einem übersichtlichen Layout im Browser anzeigen.

Warum Jinja2 wichtig ist

  • Dynamische Inhalte: Daten aus der Datenbank werden automatisch in HTML-Seiten eingefügt.
  • Trennung von Logik und Darstellung: Python-Code bleibt im Backend, während das Frontend über Templates gepflegt wird.
  • Flexibilität: Mit Schleifen, Bedingungen und Platzhaltern lassen sich komplexe Layouts einfach umsetzen.
  • Praxisnähe:

1. Daten aus der Datenbank abrufen

Bevor du die Daten an das HTML senden kannst, musst du sie mithilfe des ORM (Flask-SQLAlchemy) aus der db.db-Datei auslesen.

  • Der Abruf: Du verwendest die query-Methode deiner Message-Klasse, um alle gespeicherten Nachrichten abzufragen.
    • Message.query: Startet die Abfrage für die message-Tabelle.
    • .order_by(Message.created_at): Sortiert die Ergebnisse nach dem Zeitstempel, um sicherzustellen, dass die ältesten Nachrichten zuerst angezeigt werden.
    • .all(): Führt die Abfrage aus und gibt eine Liste von Message-Objekten zurück (z. B. [<Message 1>, <Message 2>, ...]).
nachrichten = Message.query.order_by(Message.created_at).all()
  • Das Ergebnis: Deine Python-Variable nachrichten enthält nun alle Daten, die du im Chat anzeigen möchtest.

2. Datenübergabe von Python an HTML

HTML kann standardmäßig keine Python-Variablen oder Listen verarbeiten. Flask löst dieses Problem durch die Template-Engine Jinja2:

  • Der Parameter: Die Funktion render_template() kann zusätzliche Schlüsselwortargumente entgegennehmen, die dann automatisch als Variablen im HTML-Template verfügbar sind.
  • Im Template: Im index.html-Template ist die Variable all_messages nun direkt verfügbar und enthält die Liste der Nachricht-Objekte.
# Übergabe der Python-Liste 'nachrichten' an das Template unter dem Namen 'all_messages'
return render_template('index.html', user_name=name, all_messages=nachrichten)

3. Dynamische Darstellung mit Jinja2

Innerhalb deiner index.html-Datei verwendest du spezielle Jinja2-Syntax, um die übergebenen Daten zu verarbeiten und anzuzeigen.

A. Variable Substitution ({{ ... }})

Dieser Syntax dient dazu, den Wert einer Variable direkt in den HTML-Code einzufügen.

  • Beispiel: Um den Namen des angemeldeten Benutzers in der Überschrift anzuzeigen:
<h1>Willkommen, {{ user_name }}</h1>

B. Kontrollstrukturen ({% ... %})

Dieser Syntax dient dazu, logische Anweisungen und Kontrollstrukturen wie Schleifen und Bedingungen auszuführen.

  • Die for-Schleife: Du nutzt eine for-Schleife, um die gesamte Liste der Nachrichten zu durchlaufen und für jede Nachricht den HTML-Code (die div-Struktur für die Karte) einmal zu generieren. Innerhalb der Schleife greifst du auf die Attribute des aktuellen msg-Objekts zu, z. B. {{ msg.content }} oder {{ msg.user }}.
{% for msg in all_messages %}
    <!-- Hier wird die Nachricht-Karte eingefügt -->
{% endfor %}

4. Styling-Logik im Template (Dynamische Ausrichtung)

Die letzte Herausforderung besteht darin, die richtige CSS-Klasse (justify-content-end vs. justify-content-start) dynamisch zuzuweisen, damit die Nachrichten des aktuellen Benutzers rechts und alle anderen links angezeigt werden.

  • Die if-Bedingung: Du verwendest eine Jinja2-Bedingung ({% if ... %}) innerhalb der Schleife.
  • Der Vergleich: Du vergleichst den user-Wert der aktuellen Nachricht (msg.user) mit dem Namen des Benutzers, der gerade angemeldet ist (user_name, der aus der URL übergeben wurde).
{% if msg.user == user_name %}
    <!-- Eigene Nachricht: rechts ausrichten -->
    <div class="d-flex justify-content-end">...</div>
{% else %}
    <!-- Fremde Nachricht: links ausrichten -->
    <div class="d-flex justify-content-start">...</div>
{% endif %}

Durch diese Logik wird deine statische HTML-Struktur in eine voll funktionsfähige, dynamische Chat-Oberfläche verwandelt.

Aufgabe:

Ziel: Du implementierst die Logik zum Auslesen aller gespeicherten Nachrichten aus der Datenbank und nutzt die Jinja2-Template-Engine, um diese Daten in deiner index.html-Datei als Chat-Karten darzustellen.

Schaue dir den abschließenden Abschnitt: Auslesen und Dynamisches Anzeigen (von ca. 45:00 bis zum Ende) an.

1. Datenabfrage in Python

Du beginnst damit, alle gespeicherten Nachrichten in deiner Haupt-Route abzurufen.

  • Abfrage implementieren: Finde in deiner Python-Anwendung (app.py oder api_app.py) die Hauptfunktion index(name).
  • Nachrichten abrufen: Schreibe eine Abfrage mit dem ORM, die alle Nachrichten aus der message-Tabelle abruft und sie nach dem Erstellungsdatum (created_at) sortiert:
# Speichere das Ergebnis in einer Variablen namens 'all_messages'
all_messages = Message.query.order_by(Message.created_at).all()
  • Daten übergeben: Erweitere den return render_template(...)-Aufruf, um die abgerufene Liste (all_messages) und den Benutzernamen (name) an dein HTML-Template zu übergeben:
return render_template('index.html', current_user=name, messages=all_messages)

(Hinweis: Wir nutzen hier die Variablennamen current_user und messages zur besseren Unterscheidung im Template.)

2. Dynamische Darstellung in HTML (Jinja2)

Du ersetzt nun die statischen, simulierten Nachrichten in deiner index.html durch dynamische Jinja2-Logik.

  • Statischen Code entfernen: Lösche die beiden <div class="card">-Blöcke, die du in der vorherigen Aufgabe zur Simulation eingefügt hast. Lasse nur den Haupt-Container (<div class="container">) übrig.
  • for-Schleife implementieren: Füge die Jinja2-Syntax ein, um die übergebene Liste messages zu durchlaufen:
{% for msg in messages %}
    <!-- Hier kommt die Nachricht-Karte für {{ msg.content }} hinein -->
{% endfor %}
  • Nachrichteninhalt einfügen: Kopiere den HTML-Code (inklusive der Bootstrap-Klassen wie card und card-body) wieder in die Schleife. Ersetze den statischen Text durch die Variablen-Substitution:
    • Zeige den Namen des Autors mit {{ msg.user }} an.
    • Zeige den Inhalt mit {{ msg.content }} an.
    • Füge den Zeitstempel mit {{ msg.created_at }} (ggf. mit dem Jinja2-Filter für eine schönere Formatierung) hinzu.

3. Dynamische Ausrichtung (Eigene vs. Fremde Nachricht)

Du nutzt eine if-Bedingung innerhalb der Schleife, um die Nachrichten von dir selbst immer rechts auszurichten.

  1. Bedingte Klasse: Verwende eine Jinja2-Bedingung, die den Autor der aktuellen Nachricht (msg.user) mit dem angemeldeten Benutzer (current_user) vergleicht.
  2. Implementiere die Logik: Lasse Jinja2 entscheiden, welche CSS-Klasse für die Ausrichtung des äußeren div verwendet werden soll:
{% if msg.user == current_user %}
    <div class="d-flex justify-content-end mt-3">
{% else %}
    <div class="d-flex justify-content-start mt-3">
{% endif %}

(Hinweis: Schließe die if-Bedingung am Ende des Nachrichtenblocks mit {% endif %} ab, und vergiss nicht, die for-Schleife mit {% endfor %} zu schließen.)

Erfolgsnachweis

  1. Starte deine Flask-Anwendung neu (z. B. unter http://127.0.0.1:5000/DeinName).
  2. Prüfe im Browser: Alle Nachrichten, die du in der vorherigen Aufgabe gespeichert hast, sollten nun angezeigt werden.
  3. Test der Dynamik: Wechsle den Namen in der URL (z. B. /FremderName). Alle Nachrichten, die vorher links angezeigt wurden, bleiben links. Die Nachrichten, die du als FremderName neu eingibst, sollten nun auf der rechten Seite erscheinen.

Mit dieser Aufgabe hast du den kompletten Zyklus einer Webanwendung – von der Datenbank über das Backend bis zum Frontend – abgeschlossen.

Weitere Übungen Objektorientierte Programmierung: https://informatik.bildung-rp.de/fileadmin/user_upload/informatik.bildung-rp.de/Fortbildung/pdf/PY-110831-Savoric-OOP.pdf