Abschnitt 18 · Lektion 1
Vom Skript zum Server
Fast jedes Programm in diesem Kurs fing oben an, lief bis unten und war fertig. Der Wetterdienst in
Abschnitt 17 war die Ausnahme. wetterdienst.py lief im Hintergrund, wartete auf eine Anfrage,
beantwortete sie und wartete weiter. So ein Programm nennt man Server. In diesem Abschnitt baust
du selbst einen, und zwar das Haushaltsbuch, diesmal im Browser.
Ein Skript und ein Server
Ein Skript startet, tut seine Arbeit und endet. Ein Server startet und tut erst einmal nichts. Er lauscht an einem Port, wie der Wetterdienst an Port 8000, und wartet auf eine Anfrage. Wenn eine kommt, ruft er die Funktion auf, die zu ihrer Adresse gehört, schickt die Antwort zurück und wartet wieder, so lange, bis ihn jemand beendet.
Die Anfragen kommen von einem Browser, so wie bei jeder Webseite, die du aufrufst, oder von einem Programm wie in Abschnitt 17. Für den Server macht das keinen Unterschied. Beides ist eine Anfrage an eine Adresse.
Einen Server von Hand zu bauen, so wie wetterdienst.py mit http.server, ist mühsam. Adresse
zerlegen, Parameter auslesen, Kopfzeilen schreiben, alles von Hand. Diese Arbeit nimmt dir das Paket
Flask ab. Es ist eines der bekanntesten für Web-Anwendungen in Python und bringt nur das
Nötigste mit. Was darüber hinaus nötig ist, holt man sich dazu. Hier liegt es bereit, zu Hause
installierst du es wie requests in einer virtuellen Umgebung, mit python -m pip install flask.
Die kleinste Anwendung
from flask import Flask
app = Flask(__name__)
@app.get("/")
def startseite():
return "Hallo aus dem Haushaltsbuch" Nach einem Klick auf Sandbox starten steht kurz darauf der Satz im Reiter Browser. Der Browser dort fragt wirklich deinen Server, genau wie ein Browser auf deinem Rechner.
from flask import Flask holt die Klasse Flask aus dem Paket. Mit app = Flask(__name__) wird
die Anwendung (application) angelegt. Das ist ein Objekt, in dem alles steckt, was zu deiner
Web-Anwendung gehört. Über __name__ weiß Flask, in welcher Datei sie steht, und findet so später
die Dateien, die daneben liegen.
@app.get("/") steht über einer Funktion, so wie @dataclass in Lektion 14.4 über einer Klasse
stand. Auch das ist ein Dekorator, und dieser hängt die Funktion an eine Adresse. Wenn eine Anfrage
an den Pfad / kommt, ruft Flask startseite() auf.
get heißt, dass es um Anfragen geht, mit denen jemand etwas haben will, wie bei requests.get in
Abschnitt 17. Was die Funktion mit return zurückgibt, wird die Antwort.
Wie die Anwendung startet
Zu Hause öffnest du ein Terminal in dem Ordner, in dem app.py liegt, aktivierst die virtuelle
Umgebung und tippst flask --app app run. Hinter --app steht der Name der Datei ohne .py, und
run startet den Server. Danach erscheinen ein paar Zeilen, darunter
Running on http://127.0.0.1:5000, und dann passiert nichts mehr. Der Server wartet.
Diese Adresse öffnest du im Browser. 127.0.0.1 ist wie beim Wetterdienst dein eigener Rechner, und
5000 ist der Port, den Flask nimmt, wenn man nichts anderes sagt. Beenden kannst du den Server mit
Strg+C.
Hier wird die Anwendung von der Plattform gestartet. Im Terminal steht nach dem Start die Zeile, mit
der das passiert: python -m flask --app app run --port 3000. python -m flask ist dasselbe wie
flask. Es funktioniert nur auch dort, wo das Programm flask nicht auf dem Pfad liegt, und das
ist hier so. Port 3000 ist es, weil der Reiter Browser dort fragt.
Was Flask beim Start und bei jeder Anfrage selbst ins Terminal schreibt, fehlt hier. Zu Hause siehst du es, und darunter eine rote Warnung, das sei ein Server zum Entwickeln und nicht für den Betrieb. Die stimmt. Für eine Seite, die die ganze Welt besucht, nimmt man etwas Robusteres. Zum Bauen und Ausprobieren ist er genau richtig.
Eine Seite statt Text
from flask import Flask
app = Flask(__name__)
@app.get("/")
def startseite():
return """
<h1>Haushaltsbuch</h1>
<p>Im September sind diese Ausgaben dazugekommen:</p>
<ul>
<li>Bäckerei Krume, 8,40 €</li>
<li>Kino Lichtspiel, 24,00 €</li>
<li>Stadtwerke Lindenau, 84,00 €</li>
</ul>
""" Diesmal gibt die Funktion HTML zurück, die Sprache, in der Webseiten geschrieben sind. HTML musst du
für diesen Abschnitt nicht können. Ein paar Zeichen reichen: Was zwischen <h1> und </h1> steht,
ist eine Überschrift, <p> ein Absatz, <ul> eine Liste und jedes <li> ein Punkt darin. Diese
Klammern heißen Tags. Flask schickt den Text mit der Angabe, dass es HTML ist, und der Browser macht
daraus eine Seite.
HTML geht schnell über mehrere Zeilen, deshalb steht es wie jeder lange Text in drei Anführungszeichen. Die Einrückung darin stört nicht, weil der Browser über Leerzeichen hinwegliest. Bei mehr als ein paar Zeilen wird das trotzdem unübersichtlich. Zwei Lektionen weiter kommt das HTML deshalb in eigene Dateien.
Ein Server merkt sich etwas
from flask import Flask
app = Flask(__name__)
zaehler = {"aufrufe": 0}
@app.get("/")
def startseite():
zaehler["aufrufe"] += 1
anzahl = zaehler["aufrufe"]
return f"<h1>Haushaltsbuch</h1><p>Seit dem Start {anzahl}-mal aufgerufen.</p>" Nach ein paar Klicks auf Seite neu laden, den Pfeil neben der Adresse, wächst die Zahl. Bei
jeder Anfrage ruft Flask startseite() auf. Dazwischen läuft der Server weiter und behält alles,
was er weiß, auch das Dictionary zaehler. Ein Skript finge bei jedem Start wieder bei null an.
Ein global wie in Lektion 8.5 braucht es dafür nicht. Die Funktion gibt dem Namen zaehler ja
keinen neuen Wert, sie ändert nur, was im Dictionary steht, und das darf sie.
Weg ist die Zahl, sobald der Server neu startet. Hier passiert das bei jeder Änderung am Code, weil deine Anwendung dann neu gestartet wird, damit im Browser der neue Stand steht. Zu Hause passiert es, wenn du den Server mit Strg+C beendest und wieder startest.
Was ein Server sich nur im Speicher merkt, überlebt keinen Neustart. Beim Formular für neue Ausgaben wird das wichtig.
print statt return
from flask import Flask
app = Flask(__name__)
@app.get("/")
def startseite():
print("Hallo aus dem Haushaltsbuch") Hier gibt die Funktion den Satz mit print aus, statt ihn zurückzugeben. Im Browser steht
Internal Server Error, und darunter ein Traceback, der mit dieser Zeile endet:
TypeError: The view function for 'startseite' did not return a valid response. The function either returned None or ended without a return statement.
Übersetzt heißt das: Die Funktion für startseite hat keine gültige Antwort zurückgegeben, sie hat
None zurückgegeben oder ist ohne return zu Ende gelaufen. Das ist der alte Unterschied zwischen
return und print.
In den Browser kommt nur, was die Funktion zurückgibt. Was sie mit print ausgibt, landet dort, wo
der Server läuft. Zu Hause ist das das Terminal, in dem du flask gestartet hast. Hier ist es das
Terminal, sobald du bei einer Aufgabe auf Prüfen drückst und deine Anwendung dabei abgefragt wird.
Den Traceback auf der Seite gibt es nur in der Lernplattform, damit du nicht suchen musst. Flask
selbst zeigt dem Browser nur Internal Server Error und schreibt den Rest ins Terminal. Der Grund
ist einfach. Wer deine Seite besucht, soll nicht in deinen Code schauen können.
Zum Mitnehmen
Ein Skript läuft durch und ist fertig, ein Server läuft und wartet auf Anfragen. Mit dem Paket Flask ist eine Web-Anwendung nur ein paar Zeilen lang. app = Flask(__name__) legt sie an, der Dekorator @app.get hängt eine Funktion an eine Adresse, und was die Funktion mit return zurückgibt, landet im Browser. Zu Hause startet flask --app app run die Anwendung, hier passiert das mit demselben Befehl von selbst.
Jetzt du
Basis Konto, kostenlosIm Editor änderst du die Beispiele dieser Lektion und lässt sie gleich laufen. So merkst du am schnellsten, ob es sitzt.
Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.
In diesem Kurs läuft dein Code auf einem Server. Dafür hat das Basis Konto 1 Stunde im Monat, mehr Zeit gibt es mit dem Premium Konto.
Was in dieser Lektion steckt
-
Artikel mit 4 Beispielen zum Ausprobieren
Steht hier, ohne Konto lesbar.