Webová kalkulačka

Co je cílem tohoto cvičení?

Na tomto příkladu si vyzkoušíme použít knihovnu Flask na vytvoření jednoduché webové aplikace.

Předpoklady

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.

Krok 0 – kostra programu

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>

Zpracování formuláře

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.

Řešení

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.

Řešení

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.

Řešení

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.

Řešení

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ě.

Řešení

Ošetření chyb

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.

Řešení

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.

Zjednodušení šablon

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.

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2019/brno-jaro-knihovny:flask:1",
      "title": "Webová kalkulačka",
      "html": "\n          \n    \n\n    <h1>Webov&#xE1; kalkula&#x10D;ka</h1>\n<h2>Co je c&#xED;lem tohoto cvi&#x10D;en&#xED;?</h2>\n<p>Na tomto p&#x159;&#xED;kladu si vyzkou&#x161;&#xED;me pou&#x17E;&#xED;t knihovnu Flask na vytvo&#x159;en&#xED; jednoduch&#xE9;\nwebov&#xE9; aplikace.</p>\n<h2>P&#x159;edpoklady</h2>\n<p>P&#x159;edpokl&#xE1;d&#xE1;me z&#xE1;kladn&#xED; znalost Pythonu. M&#x11B;li byste m&#xED;t po&#x10D;&#xED;ta&#x10D; s nainstalovan&#xFD;m\ninterpretem jazyka Python ve verzi aspo&#x148; 3.6. Pro za&#x10D;&#xE1;tek si tak&#xE9; vytvo&#x159;te nov&#xE9;\nvirtu&#xE1;ln&#xED; prost&#x159;ed&#xED;.</p>\n<p>D&#xE1;le se v&#xE1;m bude hodit z&#xE1;kladn&#xED; p&#x159;ehled o tom, jak funguje internet, co je to\nURL a podobn&#xE9; drobnosti. Pokud si nejste jist&#xED;, za&#x10D;n&#x11B;te <a href=\"/2019/brno-jaro-knihovny/fast-track/http/\">t&#xED;mto shrnut&#xED;m pro\nza&#x10D;&#xE1;te&#x10D;n&#xED;ky</a>.</p>\n<h2>Krok 0 &#x2013; kostra programu</h2>\n<p>Pro tento p&#x159;&#xED;klad si vysta&#x10D;&#xED;me s jedn&#xED;m zdrojov&#xFD;m souborem pro Python, ale bude\npot&#x159;ebovat i n&#x11B;kolik dal&#x161;&#xED;ch soubor&#x16F; se &#x161;ablonami.</p>\n<p>Zkop&#xED;rujte si tyto soubory do libovoln&#xE9;ho adres&#xE1;&#x159;e. &#x160;ablona mus&#xED; b&#xFD;t v\npodadres&#xE1;&#x159;i <code>templates/</code>. Zkuste program spustit pomoc&#xED; <code>flask run</code>\n(nezapome&#x148;te nejd&#x159;&#xED;v nastavit prom&#x11B;nnou <code>FLASK_APP=kalk.py</code>).</p>\n<p>V&#xFD;sledkem by m&#x11B;l b&#xFD;t jednoduch&#xFD; formul&#xE1;&#x159;, kam m&#x16F;&#x17E;eme zadat dv&#x11B; &#x10D;&#xED;sla a potom\nvybrat jednu ze &#x10D;ty&#x159; operac&#xED;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"c1\"># kalk.py</span>\n<span class=\"kn\">from</span> <span class=\"nn\">flask</span> <span class=\"kn\">import</span> <span class=\"n\">Flask</span><span class=\"p\">,</span> <span class=\"n\">render_template</span>\n\n\n<span class=\"n\">app</span> <span class=\"o\">=</span> <span class=\"n\">Flask</span><span class=\"p\">(</span><span class=\"vm\">__name__</span><span class=\"p\">)</span>\n\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s2\">&quot;/&quot;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">():</span>\n    <span class=\"k\">return</span> <span class=\"n\">render_template</span><span class=\"p\">(</span><span class=\"s2\">&quot;kalkulacka.html&quot;</span><span class=\"p\">)</span>\n</pre></div><div class=\"highlight\"><pre><span></span># templates/kalkulacka.html\n<span class=\"p\">&lt;</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">head</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>Kalkula&#x10D;ka<span class=\"p\">&lt;/</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">head</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>Kalkula&#x10D;ka<span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;POST&quot;</span> <span class=\"na\">action</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{{</span> <span class=\"nv\">url_for</span><span class=\"o\">(</span><span class=\"s2\">&quot;index&quot;</span><span class=\"o\">)</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;prvni&quot;</span><span class=\"p\">&gt;</span>Prvn&#xED; &#x10D;&#xED;slo<span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;text&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;prvni&quot;</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;druhe&quot;</span><span class=\"p\">&gt;</span>Druh&#xE9; &#x10D;&#xED;slo<span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;text&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;druhe&quot;</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;operace&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;plus&quot;</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;operace&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;minus&quot;</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;operace&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;krat&quot;</span><span class=\"p\">&gt;</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;operace&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;deleno&quot;</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\n</pre></div><h2>Zpracov&#xE1;n&#xED; formul&#xE1;&#x159;e</h2>\n<p>Pokud te&#x10F; vybereme n&#x11B;kterou z operac&#xED;, dostaneme chybu. Na&#x161;e kalkula&#x10D;ka zat&#xED;m\nnev&#xED;m, &#x17E;e by m&#x11B;la zpracov&#xE1;vat i po&#x17E;adavky metodou <code>POST</code> (kter&#xE1; se pou&#x17E;&#xED;v&#xE1; pro\nodesl&#xE1;n&#xED; formul&#xE1;&#x159;e). Naprav&#xED;me to p&#x159;id&#xE1;n&#xED;m argumentu do dekor&#xE1;tor, kde\nnastav&#xED;me <code>methods</code> na seznam s hodnotami <code>GET</code> a <code>POST</code>.</p>\n<div class=\"solution\" id=\"solution-0\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2019/brno-jaro-knihovny/beginners/webova-kalkulacka/index/solutions/0/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s2\">&quot;/&quot;</span><span class=\"p\">,</span> <span class=\"n\">methods</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;GET&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">])</span>\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">():</span>\n    <span class=\"err\">&#x2026;</span>\n</pre></div>\n    </div>\n</div><p>Te&#x10F; u&#x17E; formul&#xE1;&#x159; um&#xED;me p&#x159;ijmout, ale zat&#xED;m se kalkula&#x10D;ka po&#x159;&#xE1;d chov&#xE1;, jako by\nu&#x17E;ivatel cht&#x11B;l jenom zobrazit formul&#xE1;&#x159;. Kter&#xE1; metoda byla pou&#x17E;it&#xE1;,\npozn&#xE1;me z atributu <code>method</code> objektu <code>request</code>, kter&#xFD; pot&#x159;eba nejd&#x159;&#xED;ve\nnaimportovat.</p>\n<p>P&#x159;idejte tento import, a upravte funkci, tak, aby p&#x159;i metod&#x11B; <code>POST</code> vypsala\nn&#x11B;jakou informativn&#xED; hl&#xE1;&#x161;ku. Tak&#xE9; si m&#x16F;&#x17E;eme vypsat atribut <code>form</code>, kter&#xFD;\nobsahuje data z formul&#xE1;&#x159;e.</p>\n<div class=\"solution\" id=\"solution-1\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2019/brno-jaro-knihovny/beginners/webova-kalkulacka/index/solutions/1/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s2\">&quot;/&quot;</span><span class=\"p\">,</span> <span class=\"n\">methods</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;GET&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">])</span>\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">():</span>\n    <span class=\"k\">if</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">method</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;GET&quot;</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">render_template</span><span class=\"p\">(</span><span class=\"s2\">&quot;kalkulacka.html&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">elif</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">method</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">:</span>\n        <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"s2\">&quot;Dostali jsme data&quot;</span>\n</pre></div>\n    </div>\n</div><p><code>request.form</code> se chov&#xE1; jako slovn&#xED;k, ze kter&#xE9;ho m&#x16F;&#x17E;eme vyt&#xE1;hnout hodnoty. Na&#x161;e\n&#x161;ablona definuje kl&#xED;&#x10D;e <code>prvni</code>, <code>druhe</code> a <code>operace</code>. Prvn&#xED; dva jsou &#x10D;&#xED;sla,\nposledn&#xED; je jm&#xE9;no po&#x17E;adovan&#xE9; operace. V&#x161;echna data ale dostaneme jako &#x159;et&#x11B;zce.</p>\n<p>Spo&#x10D;&#xED;tejte v&#xFD;sledek po&#x17E;adovan&#xE9; operace a zobrazte ho v prohl&#xED;&#x17E;e&#x10D;i. N&#xE1;vratov&#xE1;\nhodnota z funkce mus&#xED; b&#xFD;t &#x159;et&#x11B;zec nebo komplikovan&#x11B;j&#x161;&#xED; objekt.</p>\n<div class=\"solution\" id=\"solution-2\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2019/brno-jaro-knihovny/beginners/webova-kalkulacka/index/solutions/2/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s2\">&quot;/&quot;</span><span class=\"p\">,</span> <span class=\"n\">methods</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;GET&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">])</span>\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">():</span>\n    <span class=\"k\">if</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">method</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;GET&quot;</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">render_template</span><span class=\"p\">(</span><span class=\"s2\">&quot;kalkulacka.html&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">elif</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">method</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">:</span>\n        <span class=\"n\">prvni</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;prvni&quot;</span><span class=\"p\">])</span>\n        <span class=\"n\">druhe</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;druhe&quot;</span><span class=\"p\">])</span>\n        <span class=\"n\">operace</span> <span class=\"o\">=</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;operace&quot;</span><span class=\"p\">]</span>\n\n        <span class=\"k\">if</span> <span class=\"n\">operace</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;plus&quot;</span><span class=\"p\">:</span>\n            <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"n\">prvni</span> <span class=\"o\">+</span> <span class=\"n\">druhe</span>\n        <span class=\"k\">elif</span> <span class=\"n\">operace</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;minus&quot;</span><span class=\"p\">:</span>\n            <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"n\">prvni</span> <span class=\"o\">-</span> <span class=\"n\">druhe</span>\n        <span class=\"o\">...</span>\n\n        <span class=\"k\">return</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">vysledek</span><span class=\"p\">)</span>\n</pre></div>\n    </div>\n</div><p>Te&#x10F; u&#x17E; bychom m&#x11B;li m&#xED;t t&#xE9;m&#x11B;&#x159; funk&#x10D;n&#xED; kalkula&#x10D;ku.</p>\n<p>Dlouh&#xE1; &#x159;ada podm&#xED;nek sice funguje, ale je to docela ukecan&#xE9; &#x159;e&#x161;en&#xED;. M&#x16F;&#x17E;eme ho\nzkusit zkr&#xE1;tit. Python nem&#xE1; konstrukci typu <code>switch</code> nebo <code>case</code>. M&#x16F;&#x17E;eme ale\ntrochu podv&#xE1;d&#x11B;t a pou&#x17E;&#xED;t slovn&#xED;k. Kl&#xED;&#x10D;i budou n&#xE1;zvy operac&#xED;, hodnotami funkce,\nkter&#xE9; danou operaci prov&#xE1;d&#xED;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s2\">&quot;/&quot;</span><span class=\"p\">,</span> <span class=\"n\">methods</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;GET&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">])</span>\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">():</span>\n    <span class=\"k\">if</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">method</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;GET&quot;</span><span class=\"p\">:</span>\n        <span class=\"k\">return</span> <span class=\"n\">render_template</span><span class=\"p\">(</span><span class=\"s2\">&quot;kalkulacka.html&quot;</span><span class=\"p\">)</span>\n    <span class=\"k\">elif</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">method</span> <span class=\"o\">==</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">:</span>\n        <span class=\"n\">vsechny_operace</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;plus&quot;</span><span class=\"p\">:</span> <span class=\"k\">lambda</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">:</span> <span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"n\">y</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;minus&quot;</span><span class=\"p\">:</span> <span class=\"k\">lambda</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">:</span> <span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">y</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;krat&quot;</span><span class=\"p\">:</span> <span class=\"k\">lambda</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">:</span> <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">y</span><span class=\"p\">,</span>\n            <span class=\"s2\">&quot;deleno&quot;</span><span class=\"p\">:</span> <span class=\"k\">lambda</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">:</span> <span class=\"n\">x</span> <span class=\"o\">/</span> <span class=\"n\">y</span><span class=\"p\">,</span>\n        <span class=\"p\">}</span>\n        <span class=\"n\">prvni</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;prvni&quot;</span><span class=\"p\">])</span>\n        <span class=\"n\">druhe</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;druhe&quot;</span><span class=\"p\">])</span>\n        <span class=\"n\">operace</span> <span class=\"o\">=</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;operace&quot;</span><span class=\"p\">]</span>\n\n        <span class=\"n\">fce</span> <span class=\"o\">=</span> <span class=\"n\">vsechny_operace</span><span class=\"p\">[</span><span class=\"n\">operace</span><span class=\"p\">]</span>\n        <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"n\">fce</span><span class=\"p\">(</span><span class=\"n\">prvni</span><span class=\"p\">,</span> <span class=\"n\">druhe</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">vysledek</span><span class=\"p\">)</span>\n</pre></div><p>Pro dal&#x161;&#xED; pokra&#x10D;ov&#xE1;n&#xED; p&#x159;&#xED;kladu m&#x16F;&#x17E;ete pou&#x17E;&#xED;t libovolnou variantu.</p>\n<p>Jako dal&#x161;&#xED; krok by bylo fajn zobrazit v&#xFD;sledek pomoc&#xED; &#x161;ablony v p&#x11B;kn&#x11B; &#x10D;iteln&#xE9;m\nform&#xE1;tu.</p>\n<p>Zkop&#xED;rujte si &#x161;ablonu <code>kalkulacka.html</code> do souboru <code>vysledek.html</code> a upravte ho\ntak, aby zobrazoval ob&#x11B; zpracovan&#xE1; &#x10D;&#xED;sla, pou&#x17E;itou operaci a v&#xFD;sledek.</p>\n<div class=\"solution\" id=\"solution-3\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2019/brno-jaro-knihovny/beginners/webova-kalkulacka/index/solutions/3/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span><span class=\"c1\"># kalk.py</span>\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s2\">&quot;/&quot;</span><span class=\"p\">,</span> <span class=\"n\">methods</span><span class=\"o\">=</span><span class=\"p\">[</span><span class=\"s2\">&quot;GET&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;POST&quot;</span><span class=\"p\">])</span>\n<span class=\"k\">def</span> <span class=\"nf\">index</span><span class=\"p\">():</span>\n        <span class=\"n\">vsechny_operace</span> <span class=\"o\">=</span> <span class=\"p\">{</span>\n            <span class=\"s2\">&quot;plus&quot;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s2\">&quot;+&quot;</span><span class=\"p\">,</span> <span class=\"k\">lambda</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">:</span> <span class=\"n\">x</span> <span class=\"o\">+</span> <span class=\"n\">y</span><span class=\"p\">),</span>\n            <span class=\"s2\">&quot;minus&quot;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s2\">&quot;-&quot;</span><span class=\"p\">,</span> <span class=\"k\">lambda</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">:</span> <span class=\"n\">x</span> <span class=\"o\">-</span> <span class=\"n\">y</span><span class=\"p\">),</span>\n            <span class=\"s2\">&quot;krat&quot;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s2\">&quot;&#xD7;&quot;</span><span class=\"p\">,</span> <span class=\"k\">lambda</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">:</span> <span class=\"n\">x</span> <span class=\"o\">*</span> <span class=\"n\">y</span><span class=\"p\">),</span>\n            <span class=\"s2\">&quot;deleno&quot;</span><span class=\"p\">:</span> <span class=\"p\">(</span><span class=\"s2\">&quot;&#xF7;&quot;</span><span class=\"p\">,</span> <span class=\"k\">lambda</span> <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span><span class=\"p\">:</span> <span class=\"n\">x</span> <span class=\"o\">/</span> <span class=\"n\">y</span><span class=\"p\">),</span>\n        <span class=\"p\">}</span>\n        <span class=\"n\">prvni</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;prvni&quot;</span><span class=\"p\">])</span>\n        <span class=\"n\">druhe</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;druhe&quot;</span><span class=\"p\">])</span>\n        <span class=\"n\">operace</span> <span class=\"o\">=</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;operace&quot;</span><span class=\"p\">]</span>\n        <span class=\"n\">op</span><span class=\"p\">,</span> <span class=\"n\">fce</span> <span class=\"o\">=</span> <span class=\"n\">vsechny_operace</span><span class=\"p\">[</span><span class=\"n\">operace</span><span class=\"p\">]</span>\n        <span class=\"n\">vysledek</span> <span class=\"o\">=</span> <span class=\"n\">fce</span><span class=\"p\">(</span><span class=\"n\">prvni</span><span class=\"p\">,</span> <span class=\"n\">druhe</span><span class=\"p\">)</span>\n        <span class=\"k\">return</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">vysledek</span><span class=\"p\">)</span>\n</pre></div><div class=\"highlight\"><pre><span></span># templates/vysledek.html\n<span class=\"p\">&lt;</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">head</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>Kalkula&#x10D;ka<span class=\"p\">&lt;/</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">head</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>Kalkula&#x10D;ka<span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n        <span class=\"cp\">{{</span> <span class=\"nv\">prvni</span> <span class=\"cp\">}}</span> <span class=\"cp\">{{</span> <span class=\"nv\">symbol</span> <span class=\"cp\">}}</span> <span class=\"cp\">{{</span> <span class=\"nv\">druhe</span> <span class=\"cp\">}}</span> = <span class=\"cp\">{{</span> <span class=\"nv\">vysledek</span> <span class=\"cp\">}}</span>\n        <span class=\"p\">&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\n</pre></div>\n    </div>\n</div><p>Dal&#x161;&#xED; drobn&#xE1; pot&#xED;&#x17E; s na&#x161;&#xED; kalkula&#x10D;kou je v tom, &#x17E;e se t&#x11B;&#x17E;ko vrac&#xED; na zad&#xE1;n&#xED;\ndal&#x161;&#xED;ho v&#xFD;po&#x10D;tu ze str&#xE1;nky s v&#xFD;sledky. To m&#x16F;&#x17E;eme opravit p&#x159;id&#xE1;n&#xED;m odkazu na\nstr&#xE1;nku s v&#xFD;sledkem. P&#x159;idejte je&#x161;t&#x11B; jeden odstavec, ve kter&#xE9;m bude odkaz na\nformul&#xE1;&#x159;.</p>\n<p>M&#xED;sto zad&#xE1;v&#xE1;n&#xED; adresy natvrdo jako <code>&quot;/&quot;</code> je lep&#x161;&#xED; pou&#x17E;&#xED;t funkci\n<code>url_for(&quot;index&quot;)</code>, kter&#xE1; bude fungovat i tehdy, a&#x17E; se rozhodneme adresu\nzm&#x11B;nit. Potom n&#xE1;m bude sta&#x10D;it zm&#x11B;nit dekor&#xE1;tor na jednom m&#xED;st&#x11B;.</p>\n<div class=\"solution\" id=\"solution-4\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2019/brno-jaro-knihovny/beginners/webova-kalkulacka/index/solutions/4/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span># templates/vysledek.html\n<span class=\"p\">&lt;</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">head</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>Kalkula&#x10D;ka<span class=\"p\">&lt;/</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">head</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>Kalkula&#x10D;ka<span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n        <span class=\"cp\">{{</span> <span class=\"nv\">prvni</span> <span class=\"cp\">}}</span> <span class=\"cp\">{{</span> <span class=\"nv\">symbol</span> <span class=\"cp\">}}</span> <span class=\"cp\">{{</span> <span class=\"nv\">druhe</span> <span class=\"cp\">}}</span> = <span class=\"cp\">{{</span> <span class=\"nv\">vysledek</span> <span class=\"cp\">}}</span>\n        <span class=\"p\">&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{{</span> <span class=\"nv\">url_for</span><span class=\"o\">(</span><span class=\"s1\">&apos;index&apos;</span><span class=\"o\">)</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>Dal&#x161;&#xED; v&#xFD;po&#x10D;et<span class=\"p\">&lt;/</span><span class=\"nt\">a</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\n</pre></div>\n    </div>\n</div><h2>O&#x161;et&#x159;en&#xED; chyb</h2>\n<p>Zkuste si, co se stane p&#x159;i zad&#xE1;n&#xED; vstup&#x16F;, kter&#xE9; nejsou &#x10D;&#xED;sla. M&#x11B;li bychom dostat\ndlouhou chybovou str&#xE1;nku, kter&#xE1; obsahuje p&#x159;&#xED;li&#x161; mnoho detail&#x16F;, kter&#xE9; ur&#x10D;it&#x11B;\nnechceme ukazovat u&#x17E;ivatel&#x16F;m. Upravte program tak, aby zachytil v&#xFD;jimku, a\nzavolal funkci <code>abort</code> s argumentem <code>400</code>. T&#xED;m prohl&#xED;&#x17E;e&#x10D;i (nebo jin&#xE9;mu\nprogramu) &#x159;ekneme, &#x17E;e zadal nespr&#xE1;vn&#xE1; data.</p>\n<div class=\"solution\" id=\"solution-5\">\n    <h3>&#x158;e&#x161;en&#xED;</h3>\n    <div class=\"solution-cover\">\n        <a href=\"/2019/brno-jaro-knihovny/beginners/webova-kalkulacka/index/solutions/5/\"><span class=\"link-text\">Uk&#xE1;zat &#x159;e&#x161;en&#xED;</span></a>\n    </div>\n    <div class=\"solution-body\" aria-hidden=\"true\">\n        <div class=\"highlight\"><pre><span></span>        <span class=\"o\">...</span>\n        <span class=\"k\">try</span><span class=\"p\">:</span>\n            <span class=\"n\">prvni</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;prvni&quot;</span><span class=\"p\">])</span>\n            <span class=\"n\">druhe</span> <span class=\"o\">=</span> <span class=\"nb\">int</span><span class=\"p\">(</span><span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;druhe&quot;</span><span class=\"p\">])</span>\n        <span class=\"k\">except</span> <span class=\"ne\">ValueError</span><span class=\"p\">:</span>\n            <span class=\"n\">abort</span><span class=\"p\">(</span><span class=\"mi\">400</span><span class=\"p\">)</span>\n        <span class=\"n\">operace</span> <span class=\"o\">=</span> <span class=\"n\">request</span><span class=\"o\">.</span><span class=\"n\">form</span><span class=\"p\">[</span><span class=\"s2\">&quot;operace&quot;</span><span class=\"p\">]</span>\n        <span class=\"o\">...</span>\n</pre></div>\n    </div>\n</div><p>Te&#x10F; dostaneme krat&#x161;&#xED; chybovou str&#xE1;nku. Co kdybychom ji ale cht&#x11B;li zm&#x11B;nit?</p>\n<p>M&#x16F;&#x17E;eme na to pou&#x17E;&#xED;t nov&#xFD; dekor&#xE1;tor: <code>errorhandler</code>. Takto ozna&#x10D;en&#xE1; funkce bude\nzavolan&#xE1; v&#x17E;dycky, kdy&#x17E; dojde dojde k zavol&#xE1;n&#xED; <code>abort(400)</code>. Stejn&#x11B; dob&#x159;e bychom\nale mohli o&#x161;et&#x159;it jakoukoli jinou v&#xFD;jimku. Z t&#xE9;to funkce m&#x16F;&#x17E;eme t&#x159;eba vr&#xE1;tit\nhezky naform&#xE1;tovanou chybu.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.errorhandler</span><span class=\"p\">(</span><span class=\"mi\">400</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">spatny_pozadavek</span><span class=\"p\">(</span><span class=\"n\">chyba</span><span class=\"p\">):</span>\n    <span class=\"k\">return</span> <span class=\"s2\">&quot;Tohle nejde po&#x10D;&#xED;tat&quot;</span><span class=\"p\">,</span> <span class=\"mi\">400</span>\n</pre></div><p>Zkuste si p&#x159;idat dal&#x161;&#xED; chybovou str&#xE1;nku pro chybu 404: vyzkou&#x161;et ji m&#x16F;&#x17E;ete\nzad&#xE1;n&#xED;m nesmysln&#xE9; adresy do prohl&#xED;&#x17E;e&#x10D;e. T&#x159;eba\n<a href=\"http://127.0.0.1:5000/neexistuju\">http://127.0.0.1:5000/neexistuju</a>.</p>\n<h2>Zjednodu&#x161;en&#xED; &#x161;ablon</h2>\n<p>Moment&#xE1;ln&#x11B; na&#x161;e aplikace pou&#x17E;&#xED;v&#xE1; dv&#x11B; &#x161;ablony. Ob&#x11B; maj&#xED; velmi podobnou\nstrukturu, li&#x161;&#xED; se pouze n&#x11B;kolika m&#xE1;lo detaily uvnit&#x159;.</p>\n<p>T&#xE9;to duplicity by bylo dobr&#xE9; se zbavit.</p>\n<p>K tomu m&#x16F;&#x17E;eme pou&#x17E;&#xED;t syst&#xE9;m zalo&#x17E;en&#xFD; na d&#x11B;di&#x10D;nosti &#x161;ablon.</p>\n<p>Vytvo&#x159;&#xED;me si novou &#x161;ablonu, kter&#xE1; obsahuje spole&#x10D;n&#xE9; &#x10D;&#xE1;sti.</p>\n<div class=\"highlight\"><pre><span></span># templates/base.html\n<span class=\"cp\">&lt;!DOCTYPE html&gt;</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">head</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>Kalkula&#x10D;ka<span class=\"p\">&lt;/</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">head</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span><span class=\"cp\">{%</span> <span class=\"k\">block</span> <span class=\"nv\">titulek</span> <span class=\"cp\">%}</span>Kalkula&#x10D;ka<span class=\"cp\">{%</span> <span class=\"k\">endblock</span> <span class=\"nv\">titulek</span> <span class=\"cp\">%}</span><span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n        <span class=\"cp\">{%</span> <span class=\"k\">block</span> <span class=\"nv\">obsah</span> <span class=\"cp\">%}</span>\n        <span class=\"cp\">{%</span> <span class=\"k\">endblock</span> <span class=\"cp\">%}</span>\n    <span class=\"p\">&lt;/</span><span class=\"nt\">body</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">html</span><span class=\"p\">&gt;</span>\n</pre></div><p>Dal&#x161;&#xED; &#x161;ablony potom budou definovat blok pojmenovan&#xFD; <code>obsah</code>. Ten se vlo&#x17E;&#xED; na\np&#x159;&#xED;slu&#x161;n&#xE9; m&#xED;sto. Stejn&#x11B; tak m&#x16F;&#x17E;eme nadefinovat <code>titulek</code>. Pro ten ale m&#xE1;me\nv&#xFD;choz&#xED; hodnotu.</p>\n<div class=\"highlight\"><pre><span></span># templates/kalkulacka.html\n<span class=\"cp\">{%</span> <span class=\"k\">extends</span> <span class=\"s2\">&quot;base.html&quot;</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">block</span> <span class=\"nv\">titulek</span> <span class=\"cp\">%}</span>\nMoje kalkula&#x10D;ka\n<span class=\"cp\">{%</span> <span class=\"k\">endblock</span> <span class=\"cp\">%}</span>\n\n<span class=\"cp\">{%</span> <span class=\"k\">block</span> <span class=\"nv\">obsah</span> <span class=\"cp\">%}</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">form</span> <span class=\"na\">method</span><span class=\"o\">=</span><span class=\"s\">&quot;POST&quot;</span> <span class=\"na\">action</span><span class=\"o\">=</span><span class=\"s\">&quot;</span><span class=\"cp\">{{</span> <span class=\"nv\">url_for</span><span class=\"o\">(</span><span class=\"s2\">&quot;index&quot;</span><span class=\"o\">)</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;prvni&quot;</span><span class=\"p\">&gt;</span>Prvn&#xED; &#x10D;&#xED;slo<span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;text&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;prvni&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;druhe&quot;</span><span class=\"p\">&gt;</span>Druh&#xE9; &#x10D;&#xED;slo<span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;text&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;druhe&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;operace&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;plus&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;operace&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;minus&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;operace&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;krat&quot;</span><span class=\"p\">&gt;</span>\n    <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;submit&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;operace&quot;</span> <span class=\"na\">value</span><span class=\"o\">=</span><span class=\"s\">&quot;deleno&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">form</span><span class=\"p\">&gt;</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endblock</span> <span class=\"cp\">%}</span>\n</pre></div><p>Na za&#x10D;&#xE1;tku nadefinujeme, &#x17E;e tato &#x161;ablona roz&#x161;i&#x159;uje &#x161;ablonu jm&#xE9;nem <code>base</code>. Potom\nnadefinujeme vlastn&#xED; titulek a nakonec samotn&#xFD; blok s obsahem str&#xE1;nky.</p>\n<p>Zkuste podle stejn&#xE9;ho vzoru zjednodu&#x161;it &#x161;ablonu pro v&#xFD;sledek.</p>\n\n\n        "
    }
  }
}