Autor Beitrag
hydemarie
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 437
Erhaltene Danke: 51



BeitragVerfasst: Mo 21.03.16 14:19 
Vor einigen Jahren wurde hier spekuliert, man müsse mit irgendwelchen Apachemodulen oder übergroßen Alleskönner-Frameworks hantieren, wenn man mal eben per Python Dinge im Web veröffentlichen will.

Muss man aber gar nicht - Flask genügt.

Flask ist ein "Microframework", also im Gegensatz zu Django nicht übermäßig komplex und/oder kompliziert, sondern auf das Wesentliche beschränkt. Auch die Template-Engine Jinja2 wird mitgeliefert, die PHPs Smarty nicht unähnlich ist. Im Folgenden soll nur einmal ein einfaches "Hallo-Welt"-Beispiel geschrieben werden.

Vorteile gegenüber PHP u.a.:

Die Syntax ist einfacher (wenn auch nicht unbedingt hübscher); nach meiner Erfahrung ist es auch und gerade für Einsteiger ziemlich leicht, ein Pythonscript beliebig zu erweitern. Dazu kommt, dass Python selbst von Haus aus einige Funktionen mitbringt, die PHP nur mit einer entsprechenden Erweiterung, die mitunter in PHP selbst "hineinkompiliert" werden muss, unterstützt. Ein sqlite3-Modul ist sogar Teil des Standards.

Für Webentwickler ist das natürlich hervorragend.

Voraussetzungen:

Python ab 3.4.0 (dort ist die Paketverwaltung "pip" standardmäßig enthalten).

Pakete installieren:

Wir brauchen eigentlich nur Flask. Installieren wir es mal:

ausblenden Quelltext
1:
python3.5 -m pip install Flask					


Ist ein Fehler aufgetreten? In der Regel erklärt die Fehlermeldung, wie man sie beseitigen kann.

Das Template:

Weil es nicht unbedingt guter Stil ist, Anwendungslogik und Ansichten miteinander zu vermischen, ist es eine gute Idee, von vornherein ein Template zu nutzen, also eine HTML-Datei mit "Platzhaltern" für dynamisch generierte Variablen. Unser Beispielprogramm soll ja nicht nur statische HTML-Seiten ausgeben - dafür bräuchten wir kein Python.

Wie wäre es damit?

ausblenden HTML-Dokument
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
<!doctype html>
<html>
<head>
<title>Python ftw</title>
</head>
<body>
{% if name %}
  <h1>Hallo, {{ name }}!</h1>
{% else %}
  <h1>Hallo, Entwickler-Ecke!</h1>
{% endif %}
</body>
</html>


Kurz erklärt: Wird dem Template kein Name übergeben, dann wird "Hallo, Entwickler-Ecke!" ausgegeben; sonst "Hallo, <Name>!". Das ist zwar ein realitätsfernes Beispiel, aber irgendwo muss man ja anfangen.

Dieses Template speichern wir im Projektordner im Unterordner templates/ als "hallo.tpl" (Dateiname und Endung sind egal, ihr könnt es also gern anders nennen; Flask sucht allerdings standardmäßig im Ordner "templates", weshalb ich die Beibehaltung einfach mal empfehlen möchte).

Allgemeines zum Routing:

Anders als PHP, aber genau wie ASP.net MVC, benötigt Flask explizite "Routen" (also virtuelle Pfade), um URLs anzusprechen. Dabei ist die Route "/" sozusagen die Startseite, "/Qwertz" wäre über meinHost/Qwertz ansprechbar und so weiter und so fort. Beliebige Verschachtelungen und sogar Variablen sind möglich.

In Flask werden Routen beliebigen Funktionen mittels Dekoratoren zugewiesen:

ausblenden Quelltext
1:
2:
3:
@app.route('/Qwertz')
def BeliebigerFunktionsname():
    return "Dies ist die Website unter /Qwertz"


Eine Funktion kann dabei mehrere Routen haben:

ausblenden Quelltext
1:
2:
3:
4:
@app.route('/Qwertz')
@app.route('/Uiopue')
def BeliebigerFunktionsname():
    return "Dies ist die Website unter /Qwertz sowie /Uiopue"


Der Code:

Bevor wir Flask nutzen können, müssen wir die Funktionen, die wir nutzen möchten, importieren. Das wären Flask selbst sowie render_template, das wir brauchen, um unser templates/hallo.tpl anstelle eines statischen Textes anzuzeigen:

ausblenden Quelltext
1:
from flask import Flask, render_template					


Flask müssen wir außerdem einmal initialisieren; am besten, indem wir das Flaskobjekt in einer Variable mit sprechendem Namen, etwa "app", verpacken:

ausblenden Quelltext
1:
app = Flask(__name__)					


Dieses "app" können wir nun nutzen, um normalen Pythoncode webtauglich zu machen. Stellt es euch als eine Art offenen Namensraum vor.

Als nächsten Schritt brauchen wir natürlich eine Methode, die unser Template aufruft, sozusagen die "Main-Methode". Da wir über Routen frei bestimmen können, welche Funktion wann genutzt wird, ist ihr Name aber vollkommen egal - nehmt statt "main" also lieber einen Namen, von dem ihr auch später noch wisst, was er tun soll:

ausblenden Quelltext
1:
2:
3:
4:
@app.route('/')
@app.route('/<nameparameter>')
def halloWeltAusgeben(nameparameter=None):
    return render_template('hallo.tpl', name=nameparameter)


Damit wird beim Aufruf einer der beiden Routen ("/" oder "/irgendwas") die Methode halloWeltAusgeben mit dem Parameter "nameparameter" aufgerufen, dessen Wert im Template in der Variablen "name" verfügbar ist - standardmäßig ist diese Variable None, also "nil" (für Delphi-Freunde). Dabei gilt: Dynamische Parameter müssen in spitzen Klammern stehen; ohne sie (@app.route('/nameparameter')) würde explizit der URL meinHost/nameparameter gesetzt.

Der Aufruf des Scripts macht aber noch gar nichts:

Zitat:
% python3.5 ./hallo.py

%


Das liegt daran, dass es keine "Mainmethode" gibt - Python liest das Script ein, wertet die Methoden aus und damit ist das Script auch schon vorbei; weshalb wir Python erst einmal mitteilen müssen, dass es einen Webserver starten soll:

ausblenden Quelltext
1:
app.run(host='0.0.0.0', port=31337, debug=True)					


Der Port ist mehr oder weniger (er darf natürlich noch nicht belegt sein) frei wählbar, "debug" empfehle ich aber eingeschaltet zu lassen. Man weiß ja nie.

Zitat:
% python3.5 ./hallo.py
* Running on 0.0.0.0:31337/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: ...


Aha! Das heißt, wir haben nun einen Webserver auf Port 31337 laufen, hinter dem unsere Anwendung liegt?

Gucken wir doch mal...

Zitat:
% curl localhost:31337


ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
<!doctype html>
<html>
<head>
<title>Python ftw</title>
</head>
<body>

  <h1>Hallo, Entwickler-Ecke!</h1>

</body>
</html>


Hmm ... und unsere Variable?

Zitat:
% curl localhost:31337/hydemarie


ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
<!doctype html>
<html>
<head>
<title>Python ftw</title>
</head>
<body>

  <h1>Hallo, hydemarie!</h1>

</body>
</html>


Nebenbei kann man im Debugger auch gleich sehen, ob die Anfrage funktioniert hat:

Zitat:
% python3.5 ./hallo.py
* Running on 0.0.0.0:31337/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: ...
127.0.0.1 - - [21/Mar/2016 13:16:23] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [21/Mar/2016 13:17:09] "GET /hydemarie HTTP/1.1" 200 -


Das sieht doch gut aus. :)

Den Rest schafft ihr allein. Viel Spaß beim Basteln!

Für diesen Beitrag haben gedankt: Christian S.