Eine erste Programmierübung mit Flask, programmiert nach einem Kurs der Microsoft Virtual Academy von Christopher Harrison und Susan Ibach (ihr Blog). Weitere Kurse und Blogs zu Python, Flask gibt es bei Channel 9 (auch diesen Kurs und diesen inhaltlich ähnlichen mit Django) und Geektrainer. Eine Liste von Blogs und Youtube Filmen zu flask, Python und bottle (eine verwandtes Framework) ist hier zu finden.
Wer den mehrstündigen erstklassigen (aber auch langfädigen) Kurs mitgemacht hat, wird mit einer kleinen Quiz-Applikation belohnt. Die Entwicklungsarbeit erfolgt mit Visual Studio 2015 mit einer lokalen Pythonumgebung sowie einer lokalen flask-Runtime. Der Kurs zeigt auch den Aufbau der Visual Studio Programmierumgebung für Python, in dem Sinne ist er sehr selbsterklärend und anfängerfreundlich.
Das Quiz wird mit dem flask Framework erstellt und enthält eine Redis-Datenbank. Die Take-Aways sind die folgenden:
- Installation von Visual Studio und Einrichtung für die Entwicklung von Python-Lösungen
- Installation von Redis
- Erstellung von Webseiten mit dem flask Framework
- Umgang mit Eingabefeldern
- Speichern und Lesen von Daten in einer Datenbank (redis)
Das Quiz ist sehr simpel, zeigt aber schon viele Funktionen: nach Aufruf der (evtl. noch lokal gehosteten) Webseite
kann unter einem Titel eine Frage eingetragen werden, die in der redis Datenbank gespeichert wird; sie geht also nicht verloren.
Die Quizfrage kann mit dem Titel hervorgeholt (/question/Rechnen, Grossschreibung beachten) und beantwortet werden, mit entsprechender Rückmeldung. Es gibt auch eine Info-Seite.
Das Projekt besteht aus diesen Dateien:
- Hauptprogramm mit app.py, routes.py, requirements.txt
- 5 statische html Dateien (AnswerQuestion.html, Correct.html, CreatedQuestion.html, CreateQuestion.html, Incorrect.html)
Diese Dateien sind hier abgebildet, ohne die gesamte Visual Studio Solution und weiteres Drumherum, das vom Internet geholt wird. Auf der MVA Webseite gibt es ausser dem Video auch PPT Präsentationejn und den originalen Source Code (der hier etwas modifiziert worden ist).
Die Datei requirements.txt wird nur intern für Visual Studio gebraucht.
requirements.txt
flask
Die app.py start das lokale flask Runtime, das von VS aufgestartet wird. Diese Datei muss nicht verändert werden.
app.py
""" This script runs the application using a development server. It contains the definition of routes and views for the application. """ # Module: flask # redis https://github.com/rgl/redis/downloads http://www.codeproject.com/Articles/715967/Running-Redis-as-a-Windows-Service from flask import Flask app = Flask(__name__) # Make the WSGI interface available at the top level so wfastcgi can get it. wsgi_app = app.wsgi_app from routes import * if __name__ == '__main__': import os HOST = os.environ.get('SERVER_HOST', 'localhost') try: PORT = int(os.environ.get('SERVER_PORT', '5555')) except ValueError: PORT = 5555 app.run(HOST, PORT)
Die Hauptlogik steckt in der routes.py
from flask import Flask, request, render_template, url_for from app import app; import redis;
# Verbinde zu redis r = redis.StrictRedis(host='localhost',port=6379,db=0, charset="utf-8", decode_responses = True);
@app.route('/') def hello(): url = url_for('submit'); link = '<a href="' + url + '">Submit Question!</a>'; return link;
@app.route('/about') def about(): # return 'We are the knights who say Ni!!'; return """<html> <head> <title> Hallo Welt!</title> </head> <body> <h1>Hallo Andreas!</h1> </body> </html>"""
@app.route('/question/<title>', methods=['GET', 'POST']) def question(title): if request.method == 'GET': # Redis code to load question # sende leeres Formular question = r.get(title+':question') return render_template('AnswerQuestion.html', question = question) elif request.method == 'POST': submittedAnswer = request.form['submittedAnswer']; # Redis code to load answer answer = r.get(title+':answer') if submittedAnswer == answer: #return "Korrekt!" return render_template('Correct.html'); else: return render_template('Incorrect.html', answer = answer, submittedAnswer = submittedAnswer);
@app.route('/submit', methods=['GET', 'POST']) def submit(): if request.method == 'GET': return render_template('CreateQuestion.html'); elif request.method == 'POST': # Daten einlesen question = request.form['question']; answer = request.form['answer']; title = request.form['title']; # Daten speichern # Redis code to save question and answer r.set(title +':question', question) r.set(title +':answer', answer) return render_template('CreatedQuestion.html', question = question); else: return "<h2>Falscher Requst</h2> ";
Schliesslich braucht es die Html-Templates.
CreateQuestion.html
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title></title> </head> <body> <div> Enter your question! </div> <form method="post"> <div> Title: <input type="text" name="title" /> </div> <div> Question: <input type="text" name="question" /> </div> <div> Answer: <input type="text" name="answer" /> </div> <div> <button type="submit">Save question</button> </div> </form> </body> </html>
CreatedQuestion.html
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>Danke für deinen Eintrag</title> </head> <body> <h2>Danke für deinen Eintrag.</h2> <div>Du hast gefragt: {{ question }}</div> </body> </html>
AnswerQuestion.html
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>Bitte Frage beantworten</title> </head> <body> <h2>Frage: {{ question }}</h2> <form method="post"> <div> <label for="answer">Antwort:</label> <input type="text" name="submittedAnswer" /> </div> <div> <button type="submit">Antwort schicken</button> </div> </form> </body> </html>
Correct.html
<!DOCTYPE html> <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>GGratulation!</title> </head> <body> <h2>Gratulation, die Antwort ist richtig!</h2> </body> </html>
Incorrect.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta charset="utf-8" /> <title>Sorry, die Antwort stimmt nicht</title> </head> <body> <h2>Sorry, die Antwort stimmt nicht</h2> <div> Die richtige Antwort ist: {{ answer }} </div> <div> Du hast gesagt: {{ submittedAnswer }} </div> </body> </html>