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 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 hello():
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
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: 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
ří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.
Tento mód je užitečný, ale nebezpečný – návštěvníkům stránky může umožnit
spustit jakýkoli Pythonní kód.
Navíc aplikaci zpomaluje.
Používejte ho proto pouze na svém počítači.
V příkladu jsme vytvořili flaskovou aplikaci (app
).
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 vytvořili takzvanou routu (cestu).
Říkáme tím, že na adrese /
bude k dispozici obsah, který vrátí
definovaná funkce.
Více různých cest lze vytvořit jednoduše přidáním další funkce.
@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.
Když vytváříte dynamický web, ne vždy můžete všechna URL znát dopředu.
Pokud například chcete zobrazit informace o uživatelích na adrese
/user/hroncok
apod., 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:
@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á číslafloat
akceptuje i desetinná čísla s tečkoupath
akceptuje text i s lomítkyOpač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):
from flask import url_for
...
url_for('profile', username='hroncok')
Tuto funkci jde použít jen uvnitř funkce obsluhující cestu, pokud ji chcete vyzkoušet například v interaktivní konzoli, můžete použít speciální kontext manager:
>>> 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ě, ale mohli byste 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.
Zatím jsou naše webové stránky poměrně nudné, protože nepoužívají HTML. 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é. Lepší je použít šablony:
from flask import render_template
@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
return render_template('hello.html', name=name)
Pak je třeba vedle souboru vytvořit složku templates
a v ní hello.html
:
<!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í v Pythonu velmi oblíbený šablonovací jazyk Jinja2.
Kompletní popis jazyka najdete v dokumentaci, ale
pro většinu stránek se obejdete s {% if %}
a {{ promenna }}
jako výše,
případně s {% for %}/{% endfor %}
.
Veškerý kontext (proměnné) do šablony musí přijít z volání render_template()
,
navíc můžete automaticky použít např. funkci url_for()
.
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ř. 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
:
{{ created_at|time }}
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 <script>alert("Foo")!</h1>
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 }}
Z 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)
Pokud budete potřebovat nějaké statické soubory (např. css soubory nebo
obrázky), dejte je do složky static
a přistupujte k nim pomocí:
url_for('static', filename='style.css')
V šabloně pak například:
<link href="{{ url_for('static', filename='style.css') }}" rel="stylesheet">
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)
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:2017/mipyt-zima:flask:0", "title": "Flask", "html": "\n \n \n\n <h1>Webové aplikace: Flask</h1>\n<p>Python je víceúčelový jazyk.\nNa minulém cvičení jsme tvořili aplikace pro příkazovou řádku,\nnyní se podíváme na aplikace webové.</p>\n<p>Webových frameworků pro Python je více, mezi nejznámější patří <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še účely použijeme Flask, protože je nejrychlejší na pochopení a\nnevyžaduje striktně použití <a href=\"https://cs.wikipedia.org/wiki/Model-view-controller\">MVC</a> paradigmatu.</p>\n<h2>Flask</h2>\n<p>Flask opět můžete nainstalovat do virtualenvu, nejlépe použít projekt\nz minulého cvičení:</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ákladní použití Flasku je poměrně primitivní.\nDo souboru <code>hello.py</code> napiš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\">'/'</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\">'MI-PYT je nejlepší předmět na FITu!'</span>\n</pre></div><p>Pak aplikaci spusťte pomocí následujících příkazů.\n(Na Windows použijte místo <code>export</code> pří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\"> * 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 code: 189-972-345</span>\n</pre></div><p>Na zmíněné adrese byste měli v prohlížeči vidět použitý text.</p>\n<p>Proměnná prostředí <code>FLASK_APP</code> říká Flasku, kde aplikaci najít.\nV daném souboru Flask hledá automaticky proměnnou jménem <code>app</code>.\n(<a href=\"http://flask.pocoo.org/docs/0.12/cli/\">Jde nastavit</a> i jiná.)</p>\n<p>Proměnná <code>FLASK_DEBUG</code> říká, že se aplikace má spustit v ladícím režimu:\nje zapnutý příjemnější výpis chyb a aplikace se automaticky restartuje\npo změnách.\nTento mód je užitečný, ale nebezpečný – návštěvníkům stránky může umožnit\nspustit jakýkoli Pythonní kód.\nNavíc aplikaci zpomaluje.\nPoužívejte ho proto pouze na svém počítači.</p>\n<p>V příkladu jsme vytvořili flaskovou aplikaci (<code>app</code>).\nArgument <code>__name__</code> je jméno modulu – Flask podle něj hledá soubory,\nkteré k aplikaci patří (viz <code>static</code> a <code>templates</code> níže).</p>\n<p>Pomocí dekorátoru <code>@app.route</code> jsme vytvořili takzvanou routu (cestu).\nŘíkáme tím, že na adrese <code>/</code> bude k dispozici obsah, který vrátí\ndefinovaná funkce.\nVíce různých cest lze vytvořit jednoduše přidáním další funkce.</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/'</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\">'Index Page'</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/hello'</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\">'Hello, World'</span>\n</pre></div><p>Na adrese <code>http://127.0.0.1:5000/hello</code> pak uvidíte druhou stránku.</p>\n<h3>Dynamické routy</h3>\n<p>Když vytváříte dynamický web, ne vždy můžete všechna URL znát dopředu.\nPokud například chcete zobrazit informace o uživatelích na adrese\n<code>/user/hroncok</code> apod., musíte použít dynamické routy:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/user/<username>'</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\">'User {}'</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ěnnou část cesty ohraničíte lomenými závorkami a použijte jako parametr\nfunkce. Pokud chcete, můžete specifikovat, na jaký obsah se pravidlo vztahuje:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/post/<int:post_id>'</span><span class=\"p\">)</span>\n</pre></div><p>Můžete použít různá pravidla, např.:</p>\n<ul>\n<li><code>string</code> akceptuje jakýkoliv text bez lomítek (výchozí)</li>\n<li><code>int</code> akceptuje celá čísla</li>\n<li><code>float</code> akceptuje i desetinná čísla s tečkou</li>\n<li><code>path</code> akceptuje text i s lomítky</li>\n</ul>\n<h3>Získání URL</h3>\n<p>Opačným způsobem jak k routám přistupovat je, když potřebujete získat URL\nnějaké stránky, například protože potřebujete zobrazit odkaz.\nK tomu se používá funkce <code>url_for()</code>, která jako první parametr bere jméno\nrouty (neboli jméno funkce, která routu obsluhuje):</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<span class=\"o\">...</span>\n<span class=\"n\">url_for</span><span class=\"p\">(</span><span class=\"s1\">'profile'</span><span class=\"p\">,</span> <span class=\"n\">username</span><span class=\"o\">=</span><span class=\"s1\">'hroncok'</span><span class=\"p\">)</span>\n</pre></div><p>Tuto funkci jde použít jen uvnitř funkce obsluhující cestu, pokud ji chcete\nvyzkoušet například v interaktivní konzoli, můžete použít speciální kontext\nmanager:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"gp\">>>> </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\">'profile'</span><span class=\"p\">,</span> <span class=\"n\">username</span><span class=\"o\">=</span><span class=\"s1\">'hroncok'</span><span class=\"p\">))</span>\n<span class=\"gp\">... </span>\n<span class=\"go\">/user/hroncok</span>\n</pre></div><p>Možná si říkáte, proč tu URL prostě nevytvořit ručně, ale mohli byste narazit\nna problém, pokud cestu později změníte – což se může stát např. i když web\nnasadíte na jiný server.</p>\n<h3>Šablony</h3>\n<p>Zatím jsou naše webové stránky poměrně nudné, protože nepoužívají HTML.\nKlidně byste mohli udělat něco jako:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/'</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\">'<html><head><title>...'</span>\n</pre></div><p>...ale asi by to nebylo příliš příjemné.\nLepší je použít šablony:</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\">'/hello/'</span><span class=\"p\">)</span>\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/hello/<name>'</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\">'hello.html'</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>Pak je třeba vedle souboru vytvořit složku <code>templates</code> a v ní <code>hello.html</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"cp\"><!doctype html></span>\n<span class=\"p\"><</span><span class=\"nt\">html</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">head</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">title</span><span class=\"p\">></span>Hello from Flask<span class=\"p\"></</span><span class=\"nt\">title</span><span class=\"p\">></span>\n <span class=\"p\"></</span><span class=\"nt\">head</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">body</span><span class=\"p\">></span>\n <span class=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">name</span> <span class=\"cp\">%}</span>\n <span class=\"p\"><</span><span class=\"nt\">h1</span><span class=\"p\">></span>Hello <span class=\"cp\">{{</span> <span class=\"nv\">name</span> <span class=\"cp\">}}</span>!<span class=\"p\"></</span><span class=\"nt\">h1</span><span class=\"p\">></span>\n <span class=\"p\"><</span><span class=\"nt\">a</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">" </span><span class=\"cp\">{{</span> <span class=\"nv\">url_for</span><span class=\"o\">(</span><span class=\"s1\">'hello'</span><span class=\"o\">)</span> <span class=\"cp\">}}</span><span class=\"s\"> "</span><span class=\"p\">></span>Go back home<span class=\"p\"></</span><span class=\"nt\">a</span><span class=\"p\">></span>\n <span class=\"cp\">{%</span> <span class=\"k\">else</span> <span class=\"cp\">%}</span>\n <span class=\"p\"><</span><span class=\"nt\">h1</span><span class=\"p\">></span>Hello, World!<span class=\"p\"></</span><span class=\"nt\">h1</span><span class=\"p\">></span>\n <span class=\"cp\">{%</span> <span class=\"k\">endif</span> <span class=\"cp\">%}</span>\n <span class=\"p\"></</span><span class=\"nt\">body</span><span class=\"p\">></span>\n<span class=\"p\"></</span><span class=\"nt\">html</span><span class=\"p\">></span>\n</pre></div><p>Šablony používají v Pythonu velmi oblíbený šablonovací jazyk <a href=\"http://jinja.pocoo.org/latest/templates/\">Jinja2</a>.\nKompletní popis jazyka najdete v <a href=\"http://jinja.pocoo.org/latest/templates/\">dokumentaci</a>, ale\npro většinu stránek se obejdete s <code>{% if %}</code> a <code>{{ promenna }}</code> jako výše,\npřípadně s <code>{% for %}/{% endfor %}</code>.</p>\n<p>Veškerý kontext (proměnné) do šablony musí přijít z volání <code>render_template()</code>,\nnavíc můžete automaticky použít např. funkci <code>url_for()</code>.</p>\n<h4>Filtry</h4>\n<p>Není úplně elegantní vzít nějaká data (např. tweety z Twitter API) a ještě před\npředáním šabloně do nich cpát svoje úpravy (např. HTML).\nOd toho jsou tu filtry. Filtr transformuje hodnotu na řetězec,\nkterý pak ukážeme uživateli.</p>\n<p>Zde je například filtr <code>time</code>, který načte čas v určitém formátu\na převede ho do jiné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\">'time'</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\">"""Convert the time format to a different one"""</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\">'%a %b </span><span class=\"si\">%d</span><span class=\"s1\"> %H:%M:%S %z %Y'</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\">'</span><span class=\"si\">%c</span><span class=\"s1\">'</span><span class=\"p\">)</span>\n\n<span class=\"nd\">@app.route</span><span class=\"p\">(</span><span class=\"s1\">'/date_example'</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\">'date_example.html'</span><span class=\"p\">,</span>\n <span class=\"n\">created_at</span><span class=\"o\">=</span><span class=\"s1\">'Tue Mar 21 15:50:59 +0000 2017'</span><span class=\"p\">,</span>\n <span class=\"p\">)</span>\n</pre></div><p>V šabloně <code>date_example.html</code>:</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ý se vkládá do šablon, jsou automaticky nahrazeny znaky, které\nmají v HTML speciální význam.\nZabraňuje se tak bezpečnostním rizikům, kdy se vstup od uživatele interpretuje\njako HTML.</p>\n<p>Například když v aplikaci výše navštívíme URL <code>/hello/<script>alert("Foo")</code>,\nbude výsledné HTML vypadat takto:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"cp\"><!doctype html></span>\n<span class=\"p\"><</span><span class=\"nt\">title</span><span class=\"p\">></span>Hello from Flask<span class=\"p\"></</span><span class=\"nt\">title</span><span class=\"p\">></span>\n\n <span class=\"p\"><</span><span class=\"nt\">h1</span><span class=\"p\">></span>Hello <span class=\"ni\">&lt;</span>script<span class=\"ni\">&gt;</span>alert(<span class=\"ni\">&#34;</span>Foo<span class=\"ni\">&#34;</span>)!<span class=\"p\"></</span><span class=\"nt\">h1</span><span class=\"p\">></span>\n</pre></div><p>Někdy je ovšem potřeba do stránky opravdu vložit HTML.\nTo se dá zajistit dvěma způsoby. Nejjednodušší je vestavěný filtr <code>safe</code>:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"cp\">{{</span> <span class=\"s2\">"<em>Text</em>"</span> <span class=\"o\">|</span> <span class=\"nf\">safe</span> <span class=\"cp\">}}</span>\n</pre></div><p>Z Pythonu pak lze použít <a href=\"http://jinja.pocoo.org/docs/dev/api/#jinja2.Markup\">jinja2.Markup</a>,\nčímž se daný text označí jako „bezpečný”.</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\">'time'</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\">"""Convert the time format to a different one"""</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\">'%a %b </span><span class=\"si\">%d</span><span class=\"s1\"> %H:%M:%S %z %Y'</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\">'<strong></span><span class=\"si\">%c</span><span class=\"s1\"></strong>'</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><h3>Statické soubory</h3>\n<p>Pokud budete potřebovat nějaké statické soubory (např. css soubory nebo\nobrázky), dejte je do složky <code>static</code> a přistupujte k nim pomocí:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"n\">url_for</span><span class=\"p\">(</span><span class=\"s1\">'static'</span><span class=\"p\">,</span> <span class=\"n\">filename</span><span class=\"o\">=</span><span class=\"s1\">'style.css'</span><span class=\"p\">)</span>\n</pre></div><p>V šabloně pak například:</p>\n<div class=\"highlight\"><pre><span></span><span class=\"p\"><</span><span class=\"nt\">link</span> <span class=\"na\">href</span><span class=\"o\">=</span><span class=\"s\">"</span><span class=\"cp\">{{</span> <span class=\"nv\">url_for</span><span class=\"o\">(</span><span class=\"s1\">'static'</span><span class=\"o\">,</span> <span class=\"nv\">filename</span><span class=\"o\">=</span><span class=\"s1\">'style.css'</span><span class=\"o\">)</span> <span class=\"cp\">}}</span><span class=\"s\">"</span> <span class=\"na\">rel</span><span class=\"o\">=</span><span class=\"s\">"stylesheet"</span><span class=\"p\">></span>\n</pre></div><h3>Vlastní podtřída Flask</h3>\n<p>Třída <code>Flask</code> je uzpůsobena k tomu, aby bylo možné snadno rozšiřovat a přepisovat \nvýchozí chování. Mimo přidávání vlastních metod lze například měnit třídy, které \nbudou použity pro HTTP požadavky a odpovědi, měnit výchozí konfiguraci <code>flask</code> a\nspoustu dalšího. Nezapomeňte volat konstruktor nadtří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\">'MI-PYT'</span><span class=\"p\">,</span> <span class=\"s1\">'best'</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\">'Hello!'</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\">'/'</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\">'/number'</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ší</h3>\n<p>Flask umí i další věci – například zpracování formulářů, chybové stránky nebo\npřesměrování.</p>\n<p>Všechno to najdete\n<a href=\"http://flask.pocoo.org/docs/0.11/quickstart/\">v dokumentaci</a>.</p>\n\n\n " } } }