Flask –Webapps mit Python erstellen
Flask ist ein schlankes Webframework der Programmiersprache Python. Es ermöglicht das Erstellen dynamischer Websites in Kombination mit HTML. Somit kann etwa auf den Einsatz von PHP verzichtet werden und die Webapp direkt in ein Pythonprogramm integriert werden. Dies ermöglicht u.a. die zeiteffiziente Erstellung einer Cloudapp.
Flask unter Windows installieren: Diese Methode funktioniert auch, wenn Python (mindestens Version 3.4 bzw. 2.7.9) nicht zu den System-Umgebungsvariablen von Windows hinzugefügt wurde. 1. Die Windows-Suche öffnen und „Python“ eingeben. 7. Mit der [Eingabetaste] ausführen.
2. Rechtsklick auf „Python (Versionsnummer)“ und im Kontextmenü „Eigenschaften“ auswählen.
3. Den Inhalt des Feldes „Ziel:“ mit der Tastenkombination [Strg] + [C] in den Arbeitsspeicher kopieren.
4. Die Windows-Suche öffnen „cmd“ eingeben und mit der [Eingabetaste] ausführen.
5. Ein Anführungszeichen ‚“‚ eintippen
6. Rechtsklick mit dem Mauszeiger in das schwarze Feld und „Einfügen“ auswählen (in Windows 10 funktioniert auch die Tastenkombination [Strg] + [V]).
7. Hinter dem Eingefügten ein Anführungszeichen ‚“‚ setzen.
8. “ -m pip install Flask“ hinter dem Anführungszeichen ergänzen. (Die Leertaste vor dem „-m“ darf nicht vergessen werden)
Das ganze sollte dann beispielsweise wie folgt aussehen:
C:\Users\Niklas>C:\Users\Niklas\AppData\Local\Programs\Python\Python36-32\python.exe -m pip install numpy
„Hallo Welt“ Webapp |
from flask import Flask app = Flask(__name__) @app.route("/") def hallo_welt(): return "Hallo Welt!" app.run()
Zunächst wird die Klasse Flask
der Bibliothek /flask
importiert. Anschließend wird diese Klasse als Objekt app
instanziiert. Übergeben wird das Attribut __name__
, der Name des ausgeführten Modules. Mit dem route()
-Decorator wird ein Eindpoint definiert, der Flaskapp übermittelt, unter welcher URL die so genannte Viewfunction hallo_welt()
ausgeführt werden soll. In diesem Fall kennzeichnet „/“ die Startseite der Webanwendung. Die bereits angesprochene Funktion hallo_welt()
gibt die Zeichenkette “Hallo Welt!“
aus.
Nun führen wir die App mit dem Pythoninterpreter aus und erhalten:
* Serving Flask app "app" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Die letzte Zeile der Ausgabe zeigt die Adresse, unter welcher die Website erreichbar ist: http://127.0.0.1:5000/
. Im Browser geöffnet, erscheint der, durch hallo_welt()
ausgegebene Text “Hallo Welt!“
.
Variablen in der URL |
Darüber hinaus können Viewfunctions Teile der URL auch als Variablen interpretieren. Gekennzeichnet werden solche Variablen durch die Syntax <variable_name>
. Optional können Konverter eingesetzt werden, die versuchen, den Input in einen speziellen Datentyp umzuwandeln. Die Syntax für URL-Variablen, gepaart mit Konvertern lautet: <konverter:variable_name>
.
string |
Akzeptiert beliebigen Text ohne Schrägstriche |
int |
Akzeptiert positive Ganzzahlen |
float |
Akzeptiert positive Gleitkommazahlen |
path |
Wie string , akzeptiert zudem Schrägstriche |
uuid |
Akzeptiert UUID Zeichenketten |
from flask import Flask app = Flask(__name__) @app.route("/any_input/<var>/") def variable_view(var): return str(var) @app.route("/quadriere/<int:var>/") def convert_variable_view(var): return str(var**2) app.run()
Die Viewfunction des obigen Quelltextes variable_view()
übernimmt den URL-Teil var
als Variable und gibt ihn als Zeichenkette formatiert wieder aus. Als Variablentext wird hier „Niklas
“ in die URL eingefügt. Das Ergebnis ist die Ausgabe selbigen Textes im Browser, wie folgend zu sehen:
Die untere Viewfunction überprüft mit dem Konverter int
, ob der Input einer Ganzzahl entspricht (siehe auch obige Tabelle). Ist dies der Fall, wird der Input in das Python-Integer-Objekt var
konvertiert. Ausgegeben wird eine Zeichenkette des quadrierten var
im Browser, wie folgend zu sehen:
Templates und Dateimanagement |
Templates (engl. Vorlagen) sind *.html
-Dateien, die von Flask wiedergegeben werden können.
Standardmäßig schreibt Flask die folgende Dateistruktur vor:
│ app.py
│
├───templates
│ index.html
│
└───static
style.css
Im folgenden Beispiel werden wir das „Starter template“ von Bootstrap4.4 mit Flask wiedergeben. Dieses Template enthält bereits sämtliche vordefinierte Styles und Skripte, die das Designen von *.html
-Dateien vereinfacht. Diese Styles (*.css
-Dateien) und Skripte (*.js
-Dateien) würden standardmäßig im static
-Ordner abgelegt, werden jedoch hier aus Internetquellen importiert. Folgenden Quellcode speichern wir als index.html
im Ordner templates
ab.
<!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.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> <title>Hello, world!</title> </head> <body> <h1>Hello, world!</h1> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> </body> </html>
Um ein Template zu rendern, muss zunächst die Methode render_template()
importiert werden. Anschließend muss diese Methode in der entsprechenden Viewfunction (hier: hallo_welt()
) ausgeführt werden und über das return
– Statement übermittelt werden. Der (erste) Parameter von render_template()
entspricht dem Namen der wiederzugebenden *.html
-Datei, welche im Ordner templates
hinterlegt ist.
from flask import Flask from flask import render_template app = Flask(__name__) @app.route("/") def hallo_welt(): return render_template('index.html') app.run()
Das Resultat der ausgeführten app.py
sieht wie folgt aus:
Variablen an Template übergeben |
Das Wiedergeben von Templates ist gut und schön, allerdings bleibt Flask mit statischen Websites unterfordert. Um die Webanwendung dynamisch zu gestalten, werden wir im Folgenden Variablen übertragen. Damit diese in das *.html
-Template integriert werden können, benötigt es einer Template Engine. Die, zu Flask mitgelieferte, hört auf den Namen Jinja2 und ähnelt von der Syntax der von Python.
Damit die Logik von Jinja2 vom *.html
-Text unterschieden werden kann, werden Delimiter verwendet:
{{ ... }}
für Ausdrücke wie Variablen{% ... %}
für Statements wieif
-Anweisungen
import random from flask import Flask from flask import render_template app = Flask(__name__) @app.route("/") def hallo_welt(): gen_nmbr = random.randint(0, 10) return render_template("index.html", rand_nmbr=gen_nmbr) app.run()
Die Änderungen in app.py
sehen das Generieren einer Zufallszahl und dessen Übermittelung an das Template vor. Dazu wird zunächst die Standartbibliothek random
importiert und in der Funktion hallo_welt()
angewandt. Dazu speichert die Methode randint()
der random
-Bibliothek eine Zufallszahl in den einschließenden Grenzen zwischen Null und Zehn in der Variablen gen_nmbr
zwischen. Übergeben wird diese Variable durch die Methode render_template()
mit dem Keywordargument rand_nmbr
. Dieses kann von Jinja2 aufgegriffen werden und in das Rendering der *.html
-Datei einfließen lassen.
<!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.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> <title>Zufallszahl</title> </head> <body> Die generierte Zufallszahl lautet: {{ rand_nmbr }} <br> {% if rand_nmbr > 5 %} {% set nmbr_bool = "Ja" %} {% else %} {% set nmbr_bool = "Nein" %} {% endif %} Ist die Zufallszahl größer als 5? {{ nmbr_bool }}! <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> </body> </html>
Zunächst geschieht das Rendern von rand_nmbr
durch den Block {{ rand_nmbr }}
. Auf den, durch >br<
gekennzeichneten Zeilenumbruch, folgt etwas Jinja2-Logik: Erst wird geprüft, ob die Variable rand_nmbr
größer als der Wert 5
ist. Ist dem der Fall, so setzt die Template Engine Jinja2 eine Variable mit dem Namen nmbr_bool
auf Ja
. Anderenfalls, ausgelöst durch das {% else %}
-Statement, nmbr_bool
auf Nein
gesetzt. Mit {% endif %}
wird der if
-Block beendet. Abschließend rendert Jinja2 die Variable nmbr_bool
als Antwort auf die Frage, ob die zufällig erzeugte Zahl größer als fünf ist.
Input aus Formfeldern |
Bis jetzt wurde lediglich Beschrieben, wie Inhalte aus dem Python-Backend auf das HTML-Frontend gerendert werden. Dieses Unterkapitel soll nun beschreiben, wie Input aus bspw. Formfeldern des Frontend in das Backend gelangen können, um dort weiterverarbeitet werden zu können.
<!doctype html> <html> <body> <form method="POST"> <input name="email-adresse" type="email" placeholder="Email Adresse"> <input name="passwort" type="password" placeholder="Passwort"> <input type="submit" value="Übernehmen"> </form> </body> </html>
Beginnen wir mit einem rein funktionalen Beispiel: Der hierüber dargestellte html
-Code definiert ein simples Formularfeld, gekennzeichnet durch das <form>
-Tag. Anfragemethoden (engl. Request methods) ermöglichen das Senden von Informationen an den Server. Da hier simuliert sensible Daten wie Email und vor allem ein Passwort an den Server übermittelt werden sollen, als Request-Methode für dieses Formular POST
definiert. Besonders geeignet ist diese Methode, weil die Informationen im Kopf (Header) einer Anfrage (Request) an den Server gesendet werden. Die input
-Felder unterscheiden sich jeweils durch ihre type
n. Diese verlangen u.a. dass das Format einer Email eingehalten wird (Text@Text.Text) und verbergen den Text eines Passworts. Durch die placeholder
wird in den Eingabefeldern ein Text angezeigt, der bei Benutzerinteraktionen durch die Eingabe ersetzt wird. Das letzte input
-Feld repräsentiert den Button Übernehmen
mit type="submit"
, um den Browser anzuweisen, die Daten an das Backend zu senden. Damit das Flask-Backend die Daten schließlich extrahieren kann, müssen die Eingabefelder mit einem beliebigen name
-Tag versehen sein.
from flask import Flask, render_template, request app = Flask(__name__) @app.route("/", methods=["GET", "POST"]) def hallo_welt(): if request.method == "POST": email = request.form["email-adresse"] password = request.form["passwort"] return f"Email Adresse: {email} <br> Passwort: {password}" return render_template("index.html") app.run()
Damit Anfragemethoden konfiguriert werden können, muss die request
-Methode zusätzlich aus der flask
-Bibliothek importiert werden. Im .route()
geschieht mit methods=["GET", "POST"]
eine Definierung zulässiger Requestmethoden. Nach wie vor gibt die Viewfunction hallo_welt()
standartmäßig das HTML-Template index.html
, das wir oben hinsichtlich der Formfelder überarbeitet haben, wieder. Neu ist die Kontrolle, ob der Request als POST
geschehen ist, wie es nur der Fall sein kann, wenn der Übernehmen
der HTML-Form durch einen User betätigt wurde. Stellt sich dies als wahr heraus, werden die übermittelten Informationen des request
anhand der, in name
-Tags aus dem HTML-Formular in die Variablen email
und password
zwischengespeichert. In einer realen Anwendung würden diese folgend etwa in einer Datenbank hinterlegt. Hier wird die Variablen über das verschachtelte return
-Statement ausgegeben.
Formfelder in schön |
Dass das Ganze optisch auch ansprechender vonstattengeht, beweist das folgende Beispiel: Das Python Backend bleibt dabei unangetastet, lediglich findet das Frontend-CSS-Framework Bootstrap, welches bereits im Kapitel „Templates und Dateimanagement“ eingeführt wurde, Verwendung.
<!doctype html> <html lang="de"> <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.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous"> <title>Input</title> </head> <body> <div class="container"> <div class="card" style="margin-top: 5%;"> <div class="card-header"> <form method="POST"> <div class="form-group"> <label for="exampleInputEmail1">Email Adresse</label> <input name="email-adresse" type="email" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp"> <small id="emailHelp" class="form-text text-muted">Wir geben Ihre Daten niemals an Dritte weiter!</small> </div> <div class="form-group"> <label for="exampleInputPassword1">Passwort</label> <input name="passwort" type="password" class="form-control" id="exampleInputPassword1"> </div> <button type="submit" class="btn btn-primary">Übernehmen</button> </form> </div> </div> </div> <!-- Optional JavaScript --> <!-- jQuery first, then Popper.js, then Bootstrap JS --> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script> </body> </html>
Es entsteht eine aufgeräumte und optisch ansprechende Eingabemaske, die sich zudem responsive verhält, also ihre Dimensionen automatisch der Browsergröße anpasst.