Na tomto příkladu si vyzkoušíme použít knihovnu Flask na vytvoření jednoduché webové aplikace.
Předpokládáme základní znalost Pythonu. Měli byste mít počítač s nainstalovaným interpretem jazyka Python ve verzi aspoň 3.6. Pro začátek si také vytvořte nové virtuální prostředí.
Dále se vám bude hodit základní přehled o tom, jak funguje internet, co je to URL a podobné drobnosti. Pokud si nejste jistí, začněte tímto shrnutím pro začátečníky.
Pro tento příklad si vystačíme s jedním zdrojovým souborem pro Python, ale bude potřebovat i několik dalších souborů se šablonami.
Zkopírujte si tyto soubory do libovolného adresáře. Šablona musí být v
podadresáři templates/
. Zkuste program spustit pomocí flask run
(nezapomeňte nejdřív nastavit proměnnou FLASK_APP=kalk.py
).
Výsledkem by měl být jednoduchý formulář, kam můžeme zadat dvě čísla a potom vybrat jednu ze čtyř operací.
# kalk.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template("kalkulacka.html")
# templates/kalkulacka.html
<html>
<head>
<title>Kalkulačka</title>
</head>
<body>
<h1>Kalkulačka</h1>
<form method="POST" action="{{ url_for("index") }}">
<label for="prvni">První číslo</label>
<input type="text" name="prvni">
<label for="druhe">Druhé číslo</label>
<input type="text" name="druhe">
<input type="submit" name="operace" value="plus">
<input type="submit" name="operace" value="minus">
<input type="submit" name="operace" value="krat">
<input type="submit" name="operace" value="deleno">
</form>
</body>
</html>
Pokud teď vybereme některou z operací, dostaneme chybu. Naše kalkulačka zatím
nevím, že by měla zpracovávat i požadavky metodou POST
(která se používá pro
odeslání formuláře). Napravíme to přidáním argumentu do dekorátor, kde
nastavíme methods
na seznam s hodnotami GET
a POST
.
Teď už formulář umíme přijmout, ale zatím se kalkulačka pořád chová, jako by
uživatel chtěl jenom zobrazit formulář. Která metoda byla použitá,
poznáme z atributu method
objektu request
, který potřeba nejdříve
naimportovat.
Přidejte tento import, a upravte funkci, tak, aby při metodě POST
vypsala
nějakou informativní hlášku. Také si můžeme vypsat atribut form
, který
obsahuje data z formuláře.
request.form
se chová jako slovník, ze kterého můžeme vytáhnout hodnoty. Naše
šablona definuje klíče prvni
, druhe
a operace
. První dva jsou čísla,
poslední je jméno požadované operace. Všechna data ale dostaneme jako řetězce.
Spočítejte výsledek požadované operace a zobrazte ho v prohlížeči. Návratová hodnota z funkce musí být řetězec nebo komplikovanější objekt.
Teď už bychom měli mít téměř funkční kalkulačku.
Dlouhá řada podmínek sice funguje, ale je to docela ukecané řešení. Můžeme ho
zkusit zkrátit. Python nemá konstrukci typu switch
nebo case
. Můžeme ale
trochu podvádět a použít slovník. Klíči budou názvy operací, hodnotami funkce,
které danou operaci provádí.
@app.route("/", methods=["GET", "POST"])
def index():
if request.method == "GET":
return render_template("kalkulacka.html")
elif request.method == "POST":
vsechny_operace = {
"plus": lambda x, y: x + y,
"minus": lambda x, y: x - y,
"krat": lambda x, y: x * y,
"deleno": lambda x, y: x / y,
}
prvni = int(request.form["prvni"])
druhe = int(request.form["druhe"])
operace = request.form["operace"]
fce = vsechny_operace[operace]
vysledek = fce(prvni, druhe)
return str(vysledek)
Pro další pokračování příkladu můžete použít libovolnou variantu.
Jako další krok by bylo fajn zobrazit výsledek pomocí šablony v pěkně čitelném formátu.
Zkopírujte si šablonu kalkulacka.html
do souboru vysledek.html
a upravte ho
tak, aby zobrazoval obě zpracovaná čísla, použitou operaci a výsledek.
Další drobná potíž s naší kalkulačkou je v tom, že se těžko vrací na zadání dalšího výpočtu ze stránky s výsledky. To můžeme opravit přidáním odkazu na stránku s výsledkem. Přidejte ještě jeden odstavec, ve kterém bude odkaz na formulář.
Místo zadávání adresy natvrdo jako "/"
je lepší použít funkci
url_for("index")
, která bude fungovat i tehdy, až se rozhodneme adresu
změnit. Potom nám bude stačit změnit dekorátor na jednom místě.
Zkuste si, co se stane při zadání vstupů, které nejsou čísla. Měli bychom dostat
dlouhou chybovou stránku, která obsahuje příliš mnoho detailů, které určitě
nechceme ukazovat uživatelům. Upravte program tak, aby zachytil výjimku, a
zavolal funkci abort
s argumentem 400
. Tím prohlížeči (nebo jinému
programu) řekneme, že zadal nesprávná data.
Teď dostaneme kratší chybovou stránku. Co kdybychom ji ale chtěli změnit?
Můžeme na to použít nový dekorátor: errorhandler
. Takto označená funkce bude
zavolaná vždycky, když dojde dojde k zavolání abort(400)
. Stejně dobře bychom
ale mohli ošetřit jakoukoli jinou výjimku. Z této funkce můžeme třeba vrátit
hezky naformátovanou chybu.
@app.errorhandler(400)
def spatny_pozadavek(chyba):
return "Tohle nejde počítat", 400
Zkuste si přidat další chybovou stránku pro chybu 404: vyzkoušet ji můžete zadáním nesmyslné adresy do prohlížeče. Třeba http://127.0.0.1:5000/neexistuju.
Momentálně naše aplikace používá dvě šablony. Obě mají velmi podobnou strukturu, liší se pouze několika málo detaily uvnitř.
Této duplicity by bylo dobré se zbavit.
K tomu můžeme použít systém založený na dědičnosti šablon.
Vytvoříme si novou šablonu, která obsahuje společné části.
# templates/base.html
<!DOCTYPE html>
<html>
<head>
<title>Kalkulačka</title>
</head>
<body>
<h1>{% block titulek %}Kalkulačka{% endblock titulek %}</h1>
{% block obsah %}
{% endblock %}
</body>
</html>
Další šablony potom budou definovat blok pojmenovaný obsah
. Ten se vloží na
příslušné místo. Stejně tak můžeme nadefinovat titulek
. Pro ten ale máme
výchozí hodnotu.
# templates/kalkulacka.html
{% extends "base.html" %}
{% block titulek %}
Moje kalkulačka
{% endblock %}
{% block obsah %}
<form method="POST" action="{{ url_for("index") }}">
<label for="prvni">První číslo</label>
<input type="text" name="prvni">
<label for="druhe">Druhé číslo</label>
<input type="text" name="druhe">
<input type="submit" name="operace" value="plus">
<input type="submit" name="operace" value="minus">
<input type="submit" name="operace" value="krat">
<input type="submit" name="operace" value="deleno">
</form>
{% endblock %}
Na začátku nadefinujeme, že tato šablona rozšiřuje šablonu jménem base
. Potom
nadefinujeme vlastní titulek a nakonec samotný blok s obsahem stránky.
Zkuste podle stejného vzoru zjednodušit šablonu pro výsledek.