Webové aplikace: Flask

Python je víceúčelový jazyk. Na minulém cvičení jsme tvořili aplikace pro příkazovou řádku, nyní se podíváme na aplikace webové.

Webových frameworků pro Python je více, mezi nejznámější patří Django, Flask nebo Pyramid.

Pro naše účely použijeme Flask, protože je nejrychlejší na pochopení a nevyžaduje striktně použití MVC paradigmatu.

Flask

Flask opět můžete nainstalovat do virtualenvu, nejlépe použít projekt z minulého cvičení:

$ cd project
$ . __venv__/bin/activate 
(__venv__) $ python -m pip install Flask

Základní použití Flasku je poměrně primitivní. Do souboru hello.py napište:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return 'MI-PYT je nejlepší předmět na FITu!'

Pak aplikaci spusťte pomocí následujících příkazů. (Na Windows použijte místo export příkaz set.)

(__venv__) $ export FLASK_APP=hello.py
(__venv__) $ export FLASK_DEBUG=1
(__venv__) $ flask run
 * Serving Flask app "hello"
 * Forcing debug mode on
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 189-972-345

Na zmíněné adrese byste měli v prohlížeči vidět použitý text.

Proměnná prostředí FLASK_APP říká Flasku, kde aplikaci najít. V daném souboru Flask hledá automaticky proměnnou jménem app. (Jde nastavit i jiná.) Proměnná FLASK_DEBUG nastavuje ladícím režim, který si popíšeme za chvíli.

V programu jsme jako app vytvořili flaskovou aplikaci. Argument __name__ je jméno modulu – Flask podle něj hledá soubory, které k aplikaci patří (viz static a templates níže).

Pomocí dekorátoru @app.route jsme zaregistrovali takzvaný view (pohled) – funkci, která vrací obsah pro danou cestu v URL. Tomuto spojení cesty a pohledové funkce se říká route (nebo počeštěně „routa“). My konkrétně říkáme, že na cestě / (tedy na „domovské stránce“) bude k dispozici obsah, který vrátí funkce index.

Více různých adres lze obsloužit jednoduše přidáním dalších funkcí:

@app.route('/')
def index():
    return 'Index Page'

@app.route('/hello/')
def hello():
    return 'Hello, World'

Na adrese http://127.0.0.1:5000/hello/ pak uvidíte druhou stránku.

Ladící režim

Proměnná FLASK_DEBUG říká, že se aplikace má spustit v ladícím režimu: je zapnutý příjemnější výpis chyb a aplikace se automaticky restartuje po změnách.

Zkuste ve funkci hello() vyvolat výjimku (například dělení nulou – 1/0) a podívat se, jak chyba v ladícím režimu „vypadá“: Flask ukáže traceback podobný tomu z příkazové řádky a navíc vám na každé úrovni umožní pomocí malé ikonky spustit konzoli. Bezpečnostní PIN k této konzoli najdete v terminálu, kde server běží.

Ladící režim je užitečný, ale nebezpečný – návštěvníkům stránky může (po prolomení celkem jednoduchého „hesla“) umožnit spustit jakýkoli pythonní kód. Navíc aplikaci zpomaluje. Používejte ho proto pouze na svém počítači.

Dynamické routy

Když vytváříte dynamický web, ne vždy můžete všechna URL znát dopředu. Budete například chctít zobrazit informace o uživatelích na adresách jako /user/hroncok/, ale nemůžete při každé registraci nového uživatele přidávat novou funkci do kódu. Musíte použít dynamické routy:

@app.route('/user/<username>/')
def profile(username):
    return 'User {}'.format(username)

Proměnnou část cesty ohraničíte lomenými závorkami a použijte jako parametr funkce. Pokud chcete, můžete specifikovat, na jaký obsah se pravidlo vztahuje. Například číselný idenifikátor článku pro adresy jako /post/42/ můžete zadat takto:

@app.route('/post/<int:post_id>/')

Můžete použít různá pravidla, např.:

  • string akceptuje jakýkoliv text bez lomítek (výchozí)
  • int akceptuje celá čísla (a pohledové funkci je předá jako int, ne text)
  • float akceptuje i desetinná čísla s tečkou (a předá je jako float)
  • path akceptuje text i s lomítky

Rout můžte definovat i víc pro jednu funkci. Často se to používá s výchozí hodnotou argumentu:

@app.route('/hello/')
@app.route('/hello/<name>/')
def hello(name='world'):
    return 'Hello, {}!'.format(name)

Získání URL

Opačným způsobem jak k routám přistupovat je, když potřebujete získat URL nějaké stránky, například protože potřebujete zobrazit odkaz. K tomu se používá funkce url_for(), která jako první parametr bere jméno routy (neboli jméno funkce, která routu obsluhuje), a pak pojmenované argumenty pro pravidla v dynamické routě:

from flask import url_for

...

@app.route('/url/')
def show_url():
    return url_for('profile', username='hroncok')

Tuto funkci jde použít jen uvnitř pohledové funkce, Pokud ji chcete vyzkoušet například v interaktivní konzoli, můžete použít speciální kontext:

>>> with app.test_request_context():
...     print(url_for('profile', username='hroncok'))
... 
/user/hroncok/

Možná si říkáte, proč tu URL prostě nevytvořit ručně. S takovým přístupem byste ale mohli narazit na problém, pokud cestu později změníte – což se může stát např. i když web nasadíte na jiný server. Generování URL vám také může zjednodušit nasazení statické verze stránek.

Pro URL v rámci vašich stránek proto doporučujeme url_for používat důsledně.

Šablony

Zatím jsou naše webové stránky poměrně nudné: obsahují jen prostý text, nepoužívají HTML.

Předpokládáme, že víte co je to HTML a CSS. Jestli ne, doporučujeme si projít základy těchto webových technologií např. na stránkách MDN.

Klidně byste mohli udělat něco jako:

@app.route('/')
def hello():
    return '<html><head><title>...'

...ale asi by to nebylo příliš příjemné. Python je jazyk dělaný na popis algoritmů, procesů a logiky spíš než obsahu. Lepší je HTML dát do zvláštního souboru a použít ho jako šablonu (angl. template). Z Flasku vypadá použití šablony takto:

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>/')
def hello(name=None):
    return render_template('hello.html', name=name)

Funkce render_template nejen vrátí HTML z daného souboru, ale umí do něj i doplnit informace, které dostane v pojmenovaných argumentech.

Ukažme si to na příkladu: vedle souboru s kódem vytvořte složku templates a v ní hello.html s tímto obsahem:

<!doctype html>
<html>
    <head>
        <title>Hello from Flask</title>
    </head>
    <body>
        {% if name %}
            <h1>Hello {{ name }}!</h1>
            <a href="{{ url_for('hello') }}">Go back home</a>
        {% else %}
            <h1>Hello, World!</h1>
        {% endif %}
    </body>
</html>

Šablony používají (jako výchozí variantu) šablonovací jazyk Jinja2, který se s Flaskem a jinými frameworky pro Python používá často. Kompletní popis jazyka najdete v dokumentaci, ale pro většinu stránek se obejdete s doplněním hodnoty ({{ promenna }}) a podmíněným obsahem ({% if %}) jako výše, případně s cyklem: {% for %}/{% endfor %}.

Veškerý kontext (proměnné) do šablony musí přijít z volání render_template(). Navíc můžete použít vybrané funkce, např. url_for(). (Jiné funkce známé z Pythonu ale použít nejdou – ač jsou podobné, je Jinja2 jiný jazyk než Python.)

Filtry

Není úplně elegantní vzít nějaká data (např. tweety z Twitter API) a ještě před předáním šabloně do nich cpát svoje úpravy (např. převod na HTML). Od toho jsou tu filtry. Filtr transformuje hodnotu na řetězec, který pak ukážeme uživateli.

Zde je například filtr time, který načte čas v určitém formátu a převede ho do jiného:

from datetime import datetime

@app.template_filter('time')
def convert_time(text):
    """Convert the time format to a different one"""
    dt = datetime.strptime(text, '%a %b %d %H:%M:%S %z %Y')
    return dt.strftime('%c')

@app.route('/date_example')
def date_example():
    return render_template(
        'date_example.html',
        created_at='Tue Mar 21 15:50:59 +0000 2017',
    )

V šabloně date_example.html se pak filtr použije pomocí svislítka:

{{ created_at|time }}

Escaping

V textu, který se vkládá do šablon, jsou automaticky nahrazeny znaky, které mají v HTML speciální význam. Zabraňuje se tak bezpečnostním rizikům, kdy se vstup od uživatele interpretuje jako HTML.

Například když v aplikaci výše navštívíme URL /hello/<script>alert("Foo")/, bude výsledné HTML vypadat takto:

<!doctype html>
<title>Hello from Flask</title>

  <h1>Hello &lt;script&gt;alert(&#34;Foo&#34;)!</h1>

Některé prohlížeče (či doplňky do nich) proti podobným útokům různým způsobem chrání. Budete-li na své stránky zkoušet „zaútočit”, zkontrolujte v konzoli URL, které vaše aplikace v požadavku reálně dostává. Pro příklad výše to může být /hello/%3Cscript%3Ealert(%22Foo%22)/.

Někdy je ovšem potřeba do stránky opravdu vložit HTML. To se dá zajistit dvěma způsoby. Nejjednodušší je vestavěný filtr safe:

{{ "<em>Text</em>" | safe }}

V Pythonu pak lze použít jinja2.Markup, čímž se daný text označí jako „bezpečný”.

import jinja2

@app.template_filter('time')
def convert_time(text):
    """Convert the time format to a different one"""
    dt = datetime.strptime(text, '%a %b %d %H:%M:%S %z %Y')
    result = dt.strftime('<strong>%c</strong>')
    return jinja2.Markup(result)

Při použití safe a Markup však vždycky myslete na to, aby nikdo (ani nikdo mnohem chytřejší než vy) nemohl na vaší stránce provést něco nekalého.

Statické soubory

Pokud budete potřebovat nějaké statické soubory (např. styly CSS nebo obrázky), dejte je do adresáře static vedle souboru s kódem a přistupujte k nim pomocí routy static:

url_for('static', filename='style.css')

V šabloně pak například:

<link href="{{ url_for('static', filename='style.css') }}" rel="stylesheet">

Vlastní podtřída Flask

Třída Flask je uzpůsobena k tomu, aby bylo možné snadno rozšiřovat a přepisovat výchozí chování. Mimo přidávání vlastních metod lze například měnit třídy, které budou použity pro HTTP požadavky a odpovědi, měnit výchozí konfiguraci flask a spoustu dalšího. Nezapomeňte volat konstruktor nadtřídy.

from flask import current_app, Flask, Response

class MIPYTResponse(Response):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.set_cookie('MI-PYT', 'best')


class GreeterApp(Flask):
    response_class = MIPYTResponse

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.greetings = 0

    def greet(self):
        self.greetings += 1
        return 'Hello!'


app = GreeterApp(__name__)


@app.route('/')
def greet():
    return current_app.greet()


@app.route('/number/')
def greetings_number():
    return str(current_app.greetings)

A další

Flask umí i další věci – například zpracování formulářů, chybové stránky nebo přesměrování.

Všechno to najdete v dokumentaci.

{
  "data": {
    "sessionMaterial": {
      "id": "session-material:2019/brno-jaro-2019-pondeli:tmp4:0",
      "title": "Flask",
      "html": "\n          \n    \n\n    <h1>Webov&#xE9; aplikace: Flask</h1>\n<p>Python je v&#xED;ce&#xFA;&#x10D;elov&#xFD; jazyk.\nNa minul&#xE9;m cvi&#x10D;en&#xED; jsme tvo&#x159;ili aplikace pro p&#x159;&#xED;kazovou &#x159;&#xE1;dku,\nnyn&#xED; se pod&#xED;v&#xE1;me na aplikace webov&#xE9;.</p>\n<p>Webov&#xFD;ch framework&#x16F; pro Python je v&#xED;ce, mezi nejzn&#xE1;m&#x11B;j&#x161;&#xED; pat&#x159;&#xED; <a href=\"https://www.djangoproject.com/\">Django</a>,\n<a href=\"http://flask.pocoo.org/\">Flask</a> nebo <a href=\"http://www.pylonsproject.org/\">Pyramid</a>.</p>\n<p>Pro na&#x161;e &#xFA;&#x10D;ely pou&#x17E;ijeme <a href=\"http://flask.pocoo.org/\">Flask</a>, proto&#x17E;e je nejrychlej&#x161;&#xED; na pochopen&#xED; a\nnevy&#x17E;aduje striktn&#x11B; pou&#x17E;it&#xED; <a href=\"https://cs.wikipedia.org/wiki/Model-view-controller\">MVC</a> paradigmatu.</p>\n<h2>Flask</h2>\n<p>Flask op&#x11B;t m&#x16F;&#x17E;ete nainstalovat do virtualenvu, nejl&#xE9;pe pou&#x17E;&#xED;t projekt\nz minul&#xE9;ho cvi&#x10D;en&#xED;:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">$ </span><span class=\"nb\">cd</span> project\n<span class=\"gp\">$ </span>. __venv__/bin/activate \n<span class=\"gp\">(__venv__) $ </span>python -m pip install Flask\n</pre></div><p>Z&#xE1;kladn&#xED; pou&#x17E;it&#xED; Flasku je pom&#x11B;rn&#x11B; primitivn&#xED;.\nDo souboru <code>hello.py</code> napi&#x161;te:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">flask</span> <span class=\"kn\">import</span> <span class=\"n\">Flask</span>\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<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/&apos;</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=\"s1\">&apos;MI-PYT je nejlep&#x161;&#xED; p&#x159;edm&#x11B;t na FITu!&apos;</span>\n</pre></div><p>Pak aplikaci spus&#x165;te pomoc&#xED; n&#xE1;sleduj&#xED;c&#xED;ch p&#x159;&#xED;kaz&#x16F;.\n(Na Windows pou&#x17E;ijte m&#xED;sto <code>export</code> p&#x159;&#xED;kaz <code>set</code>.)</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">(__venv__) $ </span><span class=\"nb\">export</span> <span class=\"nv\">FLASK_APP</span><span class=\"o\">=</span>hello.py\n<span class=\"gp\">(__venv__) $ </span><span class=\"nb\">export</span> <span class=\"nv\">FLASK_DEBUG</span><span class=\"o\">=</span><span class=\"m\">1</span>\n<span class=\"gp\">(__venv__) $ </span>flask run\n<span class=\"go\"> * Serving Flask app &quot;hello&quot;</span>\n<span class=\"go\"> * Forcing debug mode on</span>\n<span class=\"go\"> * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)</span>\n<span class=\"go\"> * Restarting with stat</span>\n<span class=\"go\"> * Debugger is active!</span>\n<span class=\"go\"> * Debugger PIN: 189-972-345</span>\n</pre></div><p>Na zm&#xED;n&#x11B;n&#xE9; adrese byste m&#x11B;li v prohl&#xED;&#x17E;e&#x10D;i vid&#x11B;t pou&#x17E;it&#xFD; text.</p>\n<p>Prom&#x11B;nn&#xE1; prost&#x159;ed&#xED; <code>FLASK_APP</code> &#x159;&#xED;k&#xE1; Flasku, kde aplikaci naj&#xED;t.\nV dan&#xE9;m souboru Flask hled&#xE1; automaticky prom&#x11B;nnou jm&#xE9;nem <code>app</code>.\n(<a href=\"http://flask.pocoo.org/docs/1.0/cli/\">Jde nastavit</a> i jin&#xE1;.)\nProm&#x11B;nn&#xE1; <code>FLASK_DEBUG</code> nastavuje lad&#xED;c&#xED;m re&#x17E;im, kter&#xFD; si pop&#xED;&#x161;eme za chv&#xED;li.</p>\n<p>V&#xA0;programu jsme jako <code>app</code> vytvo&#x159;ili flaskovou aplikaci.\nArgument <code>__name__</code> je jm&#xE9;no modulu &#x2013; Flask podle n&#x11B;j hled&#xE1; soubory,\nkter&#xE9; k aplikaci pat&#x159;&#xED; (viz <code>static</code> a <code>templates</code> n&#xED;&#x17E;e).</p>\n<p>Pomoc&#xED; dekor&#xE1;toru <a href=\"http://flask.pocoo.org/docs/1.0/api/#flask.Flask.route\"><code>@app.route</code></a> jsme zaregistrovali takzvan&#xFD; <em>view</em> (pohled) &#x2013;\nfunkci, kter&#xE1; vrac&#xED; obsah pro danou <a href=\"/2019/brno-jaro-2019-pondeli/fast-track/http/#url-anatomy\">cestu v&#xA0;URL</a>.\nTomuto spojen&#xED; cesty a pohledov&#xE9; funkce se &#x159;&#xED;k&#xE1; <em>route</em> (nebo po&#x10D;e&#x161;t&#x11B;n&#x11B; &#x201E;routa&#x201C;).\nMy konkr&#xE9;tn&#x11B; &#x159;&#xED;k&#xE1;me, &#x17E;e na cest&#x11B; <code>/</code> (tedy na &#x201E;domovsk&#xE9; str&#xE1;nce&#x201C;) bude\nk&#xA0;dispozici obsah, kter&#xFD; vr&#xE1;t&#xED; funkce <code>index</code>.</p>\n<p>V&#xED;ce r&#x16F;zn&#xFD;ch adres lze obslou&#x17E;it jednodu&#x161;e p&#x159;id&#xE1;n&#xED;m dal&#x161;&#xED;ch funkc&#xED;:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/&apos;</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=\"s1\">&apos;Index Page&apos;</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/hello/&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hello</span><span class=\"p\">():</span>\n    <span class=\"k\">return</span> <span class=\"s1\">&apos;Hello, World&apos;</span>\n</pre></div><p>Na adrese <a href=\"http://127.0.0.1:5000/hello/\"><code>http://127.0.0.1:5000/hello/</code></a> pak uvid&#xED;te druhou str&#xE1;nku.</p>\n<h3>Lad&#xED;c&#xED; re&#x17E;im</h3>\n<p>Prom&#x11B;nn&#xE1; <code>FLASK_DEBUG</code> &#x159;&#xED;k&#xE1;, &#x17E;e se aplikace m&#xE1; spustit v&#xA0;lad&#xED;c&#xED;m re&#x17E;imu:\nje zapnut&#xFD; p&#x159;&#xED;jemn&#x11B;j&#x161;&#xED; v&#xFD;pis chyb a aplikace se automaticky restartuje\npo zm&#x11B;n&#xE1;ch.</p>\n<p>Zkuste ve funkci <code>hello()</code> vyvolat v&#xFD;jimku (nap&#x159;&#xED;klad d&#x11B;len&#xED; nulou &#x2013; <code>1/0</code>)\na pod&#xED;vat se, jak chyba v&#xA0;lad&#xED;c&#xED;m re&#x17E;imu &#x201E;vypad&#xE1;&#x201C;:\nFlask uk&#xE1;&#x17E;e <em>traceback</em> podobn&#xFD; tomu z&#xA0;p&#x159;&#xED;kazov&#xE9; &#x159;&#xE1;dky a nav&#xED;c v&#xE1;m na ka&#x17E;d&#xE9;\n&#xFA;rovni umo&#x17E;n&#xED; pomoc&#xED; mal&#xE9; ikonky spustit konzoli.\nBezpe&#x10D;nostn&#xED; PIN k&#xA0;t&#xE9;to konzoli najdete v&#xA0;termin&#xE1;lu, kde server b&#x11B;&#x17E;&#xED;.</p>\n<p>Lad&#xED;c&#xED; re&#x17E;im je u&#x17E;ite&#x10D;n&#xFD;, ale nebezpe&#x10D;n&#xFD; &#x2013; n&#xE1;v&#x161;t&#x11B;vn&#xED;k&#x16F;m str&#xE1;nky m&#x16F;&#x17E;e\n(po prolomen&#xED; celkem jednoduch&#xE9;ho &#x201E;hesla&#x201C;) umo&#x17E;nit spustit jak&#xFD;koli pythonn&#xED; k&#xF3;d.\nNav&#xED;c aplikaci zpomaluje.\nPou&#x17E;&#xED;vejte ho proto <em>pouze</em> na sv&#xE9;m po&#x10D;&#xED;ta&#x10D;i.</p>\n<h3>Dynamick&#xE9; routy</h3>\n<p>Kdy&#x17E; vytv&#xE1;&#x159;&#xED;te dynamick&#xFD; web, ne v&#x17E;dy m&#x16F;&#x17E;ete v&#x161;echna URL zn&#xE1;t dop&#x159;edu.\nBudete nap&#x159;&#xED;klad chct&#xED;t zobrazit informace o u&#x17E;ivatel&#xED;ch na adres&#xE1;ch\njako <code>/user/hroncok/</code>, ale nem&#x16F;&#x17E;ete p&#x159;i ka&#x17E;d&#xE9; registraci nov&#xE9;ho u&#x17E;ivatele\np&#x159;id&#xE1;vat novou funkci do k&#xF3;du.\nMus&#xED;te pou&#x17E;&#xED;t <a href=\"http://flask.pocoo.org/docs/1.0/quickstart/#variable-rules\">dynamick&#xE9; routy</a>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/user/&lt;username&gt;/&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">profile</span><span class=\"p\">(</span><span class=\"n\">username</span><span class=\"p\">):</span>\n    <span class=\"k\">return</span> <span class=\"s1\">&apos;User {}&apos;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">username</span><span class=\"p\">)</span>\n</pre></div><p>Prom&#x11B;nnou &#x10D;&#xE1;st cesty ohrani&#x10D;&#xED;te lomen&#xFD;mi z&#xE1;vorkami a pou&#x17E;ijte jako parametr\nfunkce. Pokud chcete, m&#x16F;&#x17E;ete specifikovat, na jak&#xFD; obsah se pravidlo vztahuje.\nNap&#x159;&#xED;klad &#x10D;&#xED;seln&#xFD; idenifik&#xE1;tor &#x10D;l&#xE1;nku pro adresy jako <code>/post/42/</code> m&#x16F;&#x17E;ete zadat\ntakto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/post/&lt;int:post_id&gt;/&apos;</span><span class=\"p\">)</span>\n</pre></div><p>M&#x16F;&#x17E;ete pou&#x17E;&#xED;t r&#x16F;zn&#xE1; pravidla, nap&#x159;.:</p>\n<ul>\n<li><code>string</code> akceptuje jak&#xFD;koliv text bez lom&#xED;tek (v&#xFD;choz&#xED;)</li>\n<li><code>int</code> akceptuje cel&#xE1; &#x10D;&#xED;sla (a pohledov&#xE9; funkci je p&#x159;ed&#xE1; jako <code>int</code>, ne text)</li>\n<li><code>float</code> akceptuje i desetinn&#xE1; &#x10D;&#xED;sla s te&#x10D;kou (a p&#x159;ed&#xE1; je jako <code>float</code>)</li>\n<li><code>path</code> akceptuje text i s lom&#xED;tky</li>\n</ul>\n<p>Rout m&#x16F;&#x17E;te definovat i v&#xED;c pro jednu funkci.\n&#x10C;asto se to pou&#x17E;&#xED;v&#xE1; s&#xA0;v&#xFD;choz&#xED; hodnotou argumentu:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/hello/&apos;</span><span class=\"p\">)</span>\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/hello/&lt;name&gt;/&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hello</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"s1\">&apos;world&apos;</span><span class=\"p\">):</span>\n    <span class=\"k\">return</span> <span class=\"s1\">&apos;Hello, {}!&apos;</span><span class=\"o\">.</span><span class=\"n\">format</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"p\">)</span>\n</pre></div><h3>Z&#xED;sk&#xE1;n&#xED; URL</h3>\n<p>Opa&#x10D;n&#xFD;m zp&#x16F;sobem jak k rout&#xE1;m p&#x159;istupovat je, kdy&#x17E; pot&#x159;ebujete z&#xED;skat URL\nn&#x11B;jak&#xE9; str&#xE1;nky, nap&#x159;&#xED;klad proto&#x17E;e pot&#x159;ebujete zobrazit odkaz.\nK tomu se pou&#x17E;&#xED;v&#xE1; funkce <a href=\"http://flask.pocoo.org/docs/1.0/api/#flask.url_for\"><code>url_for()</code></a>, kter&#xE1; jako prvn&#xED; parametr bere jm&#xE9;no\nrouty (neboli jm&#xE9;no funkce, kter&#xE1; routu obsluhuje), a pak pojmenovan&#xE9; argumenty\npro pravidla v&#xA0;dynamick&#xE9; rout&#x11B;:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">flask</span> <span class=\"kn\">import</span> <span class=\"n\">url_for</span>\n\n<span class=\"o\">...</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/url/&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">show_url</span><span class=\"p\">():</span>\n    <span class=\"k\">return</span> <span class=\"n\">url_for</span><span class=\"p\">(</span><span class=\"s1\">&apos;profile&apos;</span><span class=\"p\">,</span> <span class=\"n\">username</span><span class=\"o\">=</span><span class=\"s1\">&apos;hroncok&apos;</span><span class=\"p\">)</span>\n</pre></div><p>Tuto funkci jde pou&#x17E;&#xED;t jen uvnit&#x159; pohledov&#xE9; funkce,\nPokud ji chcete vyzkou&#x161;et nap&#x159;&#xED;klad v interaktivn&#xED; konzoli,\nm&#x16F;&#x17E;ete pou&#x17E;&#xED;t speci&#xE1;ln&#xED; kontext:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"k\">with</span> <span class=\"n\">app</span><span class=\"o\">.</span><span class=\"n\">test_request_context</span><span class=\"p\">():</span>\n<span class=\"gp\">... </span>    <span class=\"k\">print</span><span class=\"p\">(</span><span class=\"n\">url_for</span><span class=\"p\">(</span><span class=\"s1\">&apos;profile&apos;</span><span class=\"p\">,</span> <span class=\"n\">username</span><span class=\"o\">=</span><span class=\"s1\">&apos;hroncok&apos;</span><span class=\"p\">))</span>\n<span class=\"gp\">... </span>\n<span class=\"go\">/user/hroncok/</span>\n</pre></div><p>Mo&#x17E;n&#xE1; si &#x159;&#xED;k&#xE1;te, pro&#x10D; tu URL prost&#x11B; nevytvo&#x159;it ru&#x10D;n&#x11B;.\nS&#xA0;takov&#xFD;m p&#x159;&#xED;stupem byste ale mohli narazit na probl&#xE9;m, pokud cestu pozd&#x11B;ji\nzm&#x11B;n&#xED;te &#x2013; co&#x17E; se m&#x16F;&#x17E;e st&#xE1;t nap&#x159;. i kdy&#x17E; web nasad&#xED;te na jin&#xFD; server.\nGenerov&#xE1;n&#xED; URL v&#xE1;m tak&#xE9; m&#x16F;&#x17E;e zjednodu&#x161;it nasazen&#xED; statick&#xE9; verze str&#xE1;nek.</p>\n<p>Pro URL v&#xA0;r&#xE1;mci va&#x161;ich str&#xE1;nek proto doporu&#x10D;ujeme <code>url_for</code> pou&#x17E;&#xED;vat d&#x16F;sledn&#x11B;.</p>\n<h3>&#x160;ablony</h3>\n<p>Zat&#xED;m jsou na&#x161;e webov&#xE9; str&#xE1;nky pom&#x11B;rn&#x11B; nudn&#xE9;: obsahuj&#xED; jen prost&#xFD; text,\nnepou&#x17E;&#xED;vaj&#xED; HTML.</p>\n<div class=\"admonition note\"><p>P&#x159;edpokl&#xE1;d&#xE1;me, &#x17E;e v&#xED;te co je to <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML\">HTML</a> a <a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS\">CSS</a>.\nJestli ne, doporu&#x10D;ujeme si proj&#xED;t z&#xE1;klady t&#x11B;chto webov&#xFD;ch technologi&#xED;\nnap&#x159;. na str&#xE1;nk&#xE1;ch <a href=\"https://developer.mozilla.org/en-US/docs/Web\">MDN</a>.</p>\n</div><p>Klidn&#x11B; byste mohli ud&#x11B;lat n&#x11B;co jako:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hello</span><span class=\"p\">():</span>\n    <span class=\"k\">return</span> <span class=\"s1\">&apos;&lt;html&gt;&lt;head&gt;&lt;title&gt;...&apos;</span>\n</pre></div><p>...ale asi by to nebylo p&#x159;&#xED;li&#x161; p&#x159;&#xED;jemn&#xE9;.\nPython je jazyk d&#x11B;lan&#xFD; na popis algoritm&#x16F;, proces&#x16F; a logiky sp&#xED;&#x161; ne&#x17E; obsahu.\nLep&#x161;&#xED; je HTML d&#xE1;t do zvl&#xE1;&#x161;tn&#xED;ho souboru a pou&#x17E;&#xED;t ho jako <em>&#x161;ablonu</em>\n(angl. <em>template</em>).\nZ&#xA0;Flasku vypad&#xE1; pou&#x17E;it&#xED; &#x161;ablony takto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">flask</span> <span class=\"kn\">import</span> <span class=\"n\">render_template</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/hello/&apos;</span><span class=\"p\">)</span>\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/hello/&lt;name&gt;/&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">hello</span><span class=\"p\">(</span><span class=\"n\">name</span><span class=\"o\">=</span><span class=\"bp\">None</span><span class=\"p\">):</span>\n    <span class=\"k\">return</span> <span class=\"n\">render_template</span><span class=\"p\">(</span><span class=\"s1\">&apos;hello.html&apos;</span><span class=\"p\">,</span> <span class=\"n\">name</span><span class=\"o\">=</span><span class=\"n\">name</span><span class=\"p\">)</span>\n</pre></div><p>Funkce <code>render_template</code> nejen vr&#xE1;t&#xED; HTML z dan&#xE9;ho souboru, ale um&#xED; do n&#x11B;j\ni doplnit informace, kter&#xE9; dostane v&#xA0;pojmenovan&#xFD;ch argumentech.</p>\n<p>Uka&#x17E;me si to na p&#x159;&#xED;kladu: vedle souboru s&#xA0;k&#xF3;dem vytvo&#x159;te slo&#x17E;ku <code>templates</code>\na v&#xA0;n&#xED; <code>hello.html</code> s&#xA0;t&#xED;mto obsahem:</p>\n<div class=\"highlight\"><pre><span></span><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>Hello from Flask<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=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">name</span> <span class=\"cp\">%}</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>Hello <span class=\"cp\">{{</span> <span class=\"nv\">name</span> <span class=\"cp\">}}</span>!<span class=\"p\">&lt;/</span><span class=\"nt\">h1</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;hello&apos;</span><span class=\"o\">)</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span><span class=\"p\">&gt;</span>Go back home<span class=\"p\">&lt;/</span><span class=\"nt\">a</span><span class=\"p\">&gt;</span>\n        <span class=\"cp\">{%</span> <span class=\"k\">else</span> <span class=\"cp\">%}</span>\n            <span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>Hello, World!<span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n        <span class=\"cp\">{%</span> <span class=\"k\">endif</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>&#x160;ablony pou&#x17E;&#xED;vaj&#xED; (jako v&#xFD;choz&#xED; variantu) &#x161;ablonovac&#xED; jazyk <a href=\"http://jinja.pocoo.org/docs/2.10/templates/\">Jinja2</a>,\nkter&#xFD; se s&#xA0;Flaskem a jin&#xFD;mi frameworky pro Python pou&#x17E;&#xED;v&#xE1; &#x10D;asto.\nKompletn&#xED; popis jazyka najdete v&#xA0;<a href=\"http://jinja.pocoo.org/docs/2.10/templates/\">dokumentaci</a>, ale\npro v&#x11B;t&#x161;inu str&#xE1;nek se obejdete s&#xA0;dopln&#x11B;n&#xED;m hodnoty (<code>{{ promenna }}</code>)\na podm&#xED;n&#x11B;n&#xFD;m obsahem (<code>{% if %}</code>) jako v&#xFD;&#x161;e,\np&#x159;&#xED;padn&#x11B; s&#xA0;<a href=\"http://jinja.pocoo.org/docs/2.10/templates/#for\">cyklem</a>: <code>{% for %}</code>/<code>{% endfor %}</code>.</p>\n<p>Ve&#x161;ker&#xFD; kontext (prom&#x11B;nn&#xE9;) do &#x161;ablony mus&#xED; p&#x159;ij&#xED;t z vol&#xE1;n&#xED; <code>render_template()</code>.\nNav&#xED;c m&#x16F;&#x17E;ete pou&#x17E;&#xED;t vybran&#xE9; funkce, nap&#x159;. <code>url_for()</code>.\n(Jin&#xE9; funkce zn&#xE1;m&#xE9; z&#xA0;Pythonu ale pou&#x17E;&#xED;t nejdou &#x2013; a&#x10D; jsou podobn&#xE9;, je Jinja2\njin&#xFD; jazyk ne&#x17E; Python.)</p>\n<h4>Filtry</h4>\n<p>Nen&#xED; &#xFA;pln&#x11B; elegantn&#xED; vz&#xED;t n&#x11B;jak&#xE1; data (nap&#x159;. tweety z&#xA0;Twitter API) a je&#x161;t&#x11B; p&#x159;ed\np&#x159;ed&#xE1;n&#xED;m &#x161;ablon&#x11B; do nich cp&#xE1;t svoje &#xFA;pravy (nap&#x159;. p&#x159;evod na HTML).\nOd toho jsou tu filtry. Filtr transformuje hodnotu na &#x159;et&#x11B;zec,\nkter&#xFD; pak uk&#xE1;&#x17E;eme u&#x17E;ivateli.</p>\n<p>Zde je nap&#x159;&#xED;klad filtr <code>time</code>, kter&#xFD; na&#x10D;te &#x10D;as v ur&#x10D;it&#xE9;m form&#xE1;tu\na p&#x159;evede ho do jin&#xE9;ho:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">datetime</span> <span class=\"kn\">import</span> <span class=\"n\">datetime</span>\n\n<span class=\"nd\">@app.template_filter</span><span class=\"p\">(</span><span class=\"s1\">&apos;time&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">convert_time</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Convert the time format to a different one&quot;&quot;&quot;</span>\n    <span class=\"n\">dt</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">strptime</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s1\">&apos;%a %b </span><span class=\"si\">%d</span><span class=\"s1\"> %H:%M:%S %z %Y&apos;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">dt</span><span class=\"o\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s1\">&apos;</span><span class=\"si\">%c</span><span class=\"s1\">&apos;</span><span class=\"p\">)</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/date_example&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">date_example</span><span class=\"p\">():</span>\n    <span class=\"k\">return</span> <span class=\"n\">render_template</span><span class=\"p\">(</span>\n        <span class=\"s1\">&apos;date_example.html&apos;</span><span class=\"p\">,</span>\n        <span class=\"n\">created_at</span><span class=\"o\">=</span><span class=\"s1\">&apos;Tue Mar 21 15:50:59 +0000 2017&apos;</span><span class=\"p\">,</span>\n    <span class=\"p\">)</span>\n</pre></div><p>V&#xA0;&#x161;ablon&#x11B; <code>date_example.html</code> se pak filtr pou&#x17E;ije pomoc&#xED; svisl&#xED;tka:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"cp\">{{</span> <span class=\"nv\">created_at</span><span class=\"o\">|</span><span class=\"nf\">time</span> <span class=\"cp\">}}</span>\n</pre></div><h4>Escaping</h4>\n<p>V textu, kter&#xFD; se vkl&#xE1;d&#xE1; do &#x161;ablon, jsou automaticky nahrazeny znaky, kter&#xE9;\nmaj&#xED; v HTML speci&#xE1;ln&#xED; v&#xFD;znam.\nZabra&#x148;uje se tak bezpe&#x10D;nostn&#xED;m rizik&#x16F;m, kdy se vstup od u&#x17E;ivatele interpretuje\njako HTML.</p>\n<p>Nap&#x159;&#xED;klad kdy&#x17E; v aplikaci v&#xFD;&#x161;e nav&#x161;t&#xED;v&#xED;me URL <code>/hello/&lt;script&gt;alert(&quot;Foo&quot;)/</code>,\nbude v&#xFD;sledn&#xE9; HTML vypadat takto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"cp\">&lt;!doctype html&gt;</span>\n<span class=\"p\">&lt;</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>Hello from Flask<span class=\"p\">&lt;/</span><span class=\"nt\">title</span><span class=\"p\">&gt;</span>\n\n  <span class=\"p\">&lt;</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>Hello <span class=\"ni\">&amp;lt;</span>script<span class=\"ni\">&amp;gt;</span>alert(<span class=\"ni\">&amp;#34;</span>Foo<span class=\"ni\">&amp;#34;</span>)!<span class=\"p\">&lt;/</span><span class=\"nt\">h1</span><span class=\"p\">&gt;</span>\n</pre></div><div class=\"admonition note\"><p>N&#x11B;kter&#xE9; prohl&#xED;&#x17E;e&#x10D;e (&#x10D;i dopl&#x148;ky do nich) proti podobn&#xFD;m &#xFA;tok&#x16F;m r&#x16F;zn&#xFD;m zp&#x16F;sobem\nchr&#xE1;n&#xED;. Budete-li na sv&#xE9; str&#xE1;nky zkou&#x161;et &#x201E;za&#xFA;to&#x10D;it&#x201D;, zkontrolujte v&#xA0;konzoli\nURL, kter&#xE9; va&#x161;e aplikace v&#xA0;po&#x17E;adavku re&#xE1;ln&#x11B; dost&#xE1;v&#xE1;.\nPro p&#x159;&#xED;klad v&#xFD;&#x161;e to m&#x16F;&#x17E;e b&#xFD;t <code>/hello/%3Cscript%3Ealert(%22Foo%22)/</code>.</p>\n</div><p>N&#x11B;kdy je ov&#x161;em pot&#x159;eba do str&#xE1;nky opravdu vlo&#x17E;it HTML.\nTo se d&#xE1; zajistit dv&#x11B;ma zp&#x16F;soby. Nejjednodu&#x161;&#x161;&#xED; je vestav&#x11B;n&#xFD; filtr <code>safe</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"cp\">{{</span> <span class=\"s2\">&quot;&lt;em&gt;Text&lt;/em&gt;&quot;</span> <span class=\"o\">|</span> <span class=\"nf\">safe</span> <span class=\"cp\">}}</span>\n</pre></div><p>V&#xA0;Pythonu pak lze pou&#x17E;&#xED;t <a href=\"http://jinja.pocoo.org/docs/dev/api/#jinja2.Markup\">jinja2.Markup</a>,\n&#x10D;&#xED;m&#x17E; se dan&#xFD; text ozna&#x10D;&#xED; jako &#x201E;bezpe&#x10D;n&#xFD;&#x201D;.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">import</span> <span class=\"nn\">jinja2</span>\n\n<span class=\"nd\">@app.template_filter</span><span class=\"p\">(</span><span class=\"s1\">&apos;time&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">convert_time</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">):</span>\n    <span class=\"sd\">&quot;&quot;&quot;Convert the time format to a different one&quot;&quot;&quot;</span>\n    <span class=\"n\">dt</span> <span class=\"o\">=</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">strptime</span><span class=\"p\">(</span><span class=\"n\">text</span><span class=\"p\">,</span> <span class=\"s1\">&apos;%a %b </span><span class=\"si\">%d</span><span class=\"s1\"> %H:%M:%S %z %Y&apos;</span><span class=\"p\">)</span>\n    <span class=\"n\">result</span> <span class=\"o\">=</span> <span class=\"n\">dt</span><span class=\"o\">.</span><span class=\"n\">strftime</span><span class=\"p\">(</span><span class=\"s1\">&apos;&lt;strong&gt;</span><span class=\"si\">%c</span><span class=\"s1\">&lt;/strong&gt;&apos;</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">jinja2</span><span class=\"o\">.</span><span class=\"n\">Markup</span><span class=\"p\">(</span><span class=\"n\">result</span><span class=\"p\">)</span>\n</pre></div><p>P&#x159;i pou&#x17E;it&#xED; <code>safe</code> a <code>Markup</code> v&#x161;ak v&#x17E;dycky myslete na to, aby nikdo\n(ani nikdo mnohem chyt&#x159;ej&#x161;&#xED; ne&#x17E; vy) nemohl na va&#x161;&#xED; str&#xE1;nce prov&#xE9;st n&#x11B;co\nnekal&#xE9;ho.</p>\n<h3>Statick&#xE9; soubory</h3>\n<p>Pokud budete pot&#x159;ebovat n&#x11B;jak&#xE9; statick&#xE9; soubory (nap&#x159;. styly CSS nebo\nobr&#xE1;zky), dejte je do adres&#xE1;&#x159;e <code>static</code> vedle souboru s k&#xF3;dem\na p&#x159;istupujte k&#xA0;nim pomoc&#xED; routy <code>static</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">url_for</span><span class=\"p\">(</span><span class=\"s1\">&apos;static&apos;</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"o\">=</span><span class=\"s1\">&apos;style.css&apos;</span><span class=\"p\">)</span>\n</pre></div><p>V &#x161;ablon&#x11B; pak nap&#x159;&#xED;klad:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"p\">&lt;</span><span class=\"nt\">link</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;static&apos;</span><span class=\"o\">,</span> <span class=\"nv\">filename</span><span class=\"o\">=</span><span class=\"s1\">&apos;style.css&apos;</span><span class=\"o\">)</span> <span class=\"cp\">}}</span><span class=\"s\">&quot;</span> <span class=\"na\">rel</span><span class=\"o\">=</span><span class=\"s\">&quot;stylesheet&quot;</span><span class=\"p\">&gt;</span>\n</pre></div><h3>Vlastn&#xED; podt&#x159;&#xED;da Flask</h3>\n<p>T&#x159;&#xED;da <code>Flask</code> je uzp&#x16F;sobena k tomu, aby bylo mo&#x17E;n&#xE9; snadno roz&#x161;i&#x159;ovat a p&#x159;episovat \nv&#xFD;choz&#xED; chov&#xE1;n&#xED;. Mimo p&#x159;id&#xE1;v&#xE1;n&#xED; vlastn&#xED;ch metod lze nap&#x159;&#xED;klad m&#x11B;nit t&#x159;&#xED;dy, kter&#xE9; \nbudou pou&#x17E;ity pro HTTP po&#x17E;adavky a odpov&#x11B;di, m&#x11B;nit v&#xFD;choz&#xED; konfiguraci <code>flask</code> a\nspoustu dal&#x161;&#xED;ho. Nezapome&#x148;te volat konstruktor nadt&#x159;&#xED;dy.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"kn\">from</span> <span class=\"nn\">flask</span> <span class=\"kn\">import</span> <span class=\"n\">current_app</span><span class=\"p\">,</span> <span class=\"n\">Flask</span><span class=\"p\">,</span> <span class=\"n\">Response</span>\n\n<span class=\"k\">class</span> <span class=\"nc\">MIPYTResponse</span><span class=\"p\">(</span><span class=\"n\">Response</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">set_cookie</span><span class=\"p\">(</span><span class=\"s1\">&apos;MI-PYT&apos;</span><span class=\"p\">,</span> <span class=\"s1\">&apos;best&apos;</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">GreeterApp</span><span class=\"p\">(</span><span class=\"n\">Flask</span><span class=\"p\">):</span>\n    <span class=\"n\">response_class</span> <span class=\"o\">=</span> <span class=\"n\">MIPYTResponse</span>\n\n    <span class=\"k\">def</span> <span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> <span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">):</span>\n        <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span><span class=\"fm\">__init__</span><span class=\"p\">(</span><span class=\"o\">*</span><span class=\"n\">args</span><span class=\"p\">,</span> <span class=\"o\">**</span><span class=\"n\">kwargs</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">greetings</span> <span class=\"o\">=</span> <span class=\"mi\">0</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">greet</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">greetings</span> <span class=\"o\">+=</span> <span class=\"mi\">1</span>\n        <span class=\"k\">return</span> <span class=\"s1\">&apos;Hello!&apos;</span>\n\n\n<span class=\"n\">app</span> <span class=\"o\">=</span> <span class=\"n\">GreeterApp</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=\"s1\">&apos;/&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">greet</span><span class=\"p\">():</span>\n    <span class=\"k\">return</span> <span class=\"n\">current_app</span><span class=\"o\">.</span><span class=\"n\">greet</span><span class=\"p\">()</span>\n\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">&apos;/number/&apos;</span><span class=\"p\">)</span>\n<span class=\"k\">def</span> <span class=\"nf\">greetings_number</span><span class=\"p\">():</span>\n    <span class=\"k\">return</span> <span class=\"nb\">str</span><span class=\"p\">(</span><span class=\"n\">current_app</span><span class=\"o\">.</span><span class=\"n\">greetings</span><span class=\"p\">)</span>\n</pre></div><h3>A dal&#x161;&#xED;</h3>\n<p>Flask um&#xED; i dal&#x161;&#xED; v&#x11B;ci &#x2013; nap&#x159;&#xED;klad zpracov&#xE1;n&#xED; formul&#xE1;&#x159;&#x16F;, chybov&#xE9; str&#xE1;nky nebo\np&#x159;esm&#x11B;rov&#xE1;n&#xED;.</p>\n<p>V&#x161;echno to najdete\n<a href=\"http://flask.pocoo.org/docs/1.0/quickstart/\">v dokumentaci</a>.</p>\n\n\n        "
    }
  }
}