Lekce 3 - WTForms a Jinja2 šablony pro Flask framework
V minulé lekci, Seznámení s Flask microframeworkem, jsme si vytvořili aplikaci Kalkulačka, abychom si ukázali, jak fungují formuláře a jak z nich získat data.
V dnešním Python tutoriálu si ukážeme, jak vytvořit formulář ještě lépe pomocí knihovny WTForms. Ty podporují např. automatické validace na straně serveru nebo ochranu proti CSRF útoku. To jsou poměrně základní funkce, které od formulářů u aplikací požadujeme, a proto budeme knihovnu i nadále používat.
WTForms
Abychom si mohli vůbec nějaký ten formulář vytvořit, musíme si toto "rozšíření" nainstalovat pomocí nástroje pip:
py -m pip install flask-wtf
Pokud instalace WTForms proběhla úspěšně, uvidíte výstup podobný tomuto:
C:\Users\David>py -m pip install flask-wtf Collecting flask-wtf Downloading https://files.pythonhosted.org/packages/60/3a/58c629472d10539ae516 7dc7c1fecfa95dd7d0b7864623931e3776438a24/Flask_WTF-0.14.2-py2.py3-none-any.whl Requirement already satisfied: Flask in c:\users\david\appdata\local\programs\py thon\python36-32\lib\site-packages (from flask-wtf) Collecting WTForms (from flask-wtf) Downloading https://files.pythonhosted.org/packages/9f/c8/dac5dce9908df1d9d48e c0e26e2a250839fa36ea2c602cc4f85ccfeb5c65/WTForms-2.2.1-py2.py3-none-any.whl (166 kB) 100% |████████████████████████████████| 174kB 2.2MB/s Requirement already satisfied: Jinja2>=2.10 in c:\users\david\appdata\local\prog rams\python\python36-32\lib\site-packages (from Flask->flask-wtf) Requirement already satisfied: click>=5.1 in c:\users\david\appdata\local\progra ms\python\python36-32\lib\site-packages (from Flask->flask-wtf) Requirement already satisfied: Werkzeug>=0.14 in c:\users\david\appdata\local\pr ograms\python\python36-32\lib\site-packages (from Flask->flask-wtf) Requirement already satisfied: itsdangerous>=0.24 in c:\users\david\appdata\loca l\programs\python\python36-32\lib\site-packages (from Flask->flask-wtf) Requirement already satisfied: MarkupSafe>=0.23 in c:\users\david\appdata\local\ programs\python\python36-32\lib\site-packages (from Jinja2>=2.10->Flask->flask-w tf) Installing collected packages: WTForms, flask-wtf Successfully installed WTForms-2.2.1 flask-wtf-0.14.2 C:\Users\David>
Použijeme aplikaci z minulé lekce s tím rozdílem, že formulář vytvoříme pomocí WTForms:
# Importujeme from flask_wtf import FlaskForm from wtforms import SelectField, IntegerField, widgets app = Flask(__name__) # Musíme nastavit SECRET_KEY, pokud chceme používat CSRF app.config["SECRET_KEY"] = "super tajny klic" class MujFormular(FlaskForm): prvni_cislo = IntegerField("První Číslo", widget = widgets.Input(input_type = "number")) operator = SelectField("Operátor", choices=[("+" ,"+"), ("-", "-"), ("*", "*"), ("/", "/")]) druhe_cislo = IntegerField("Druhé Číslo", widget = widgets.Input(input_type = "number")) @app.route("/", methods = ["GET", "POST"]) def kalkulacka(): form = MujFormular() if form.validate_on_submit(): prvni_cislo = form.prvni_cislo.data druhe_cislo = form.druhe_cislo.data operator = form.operator.data vysledek = eval( str(prvni_cislo) + operator + str(druhe_cislo) ) return render_template("template.html", vysledek = vysledek, form = form) return render_template("template.html", form = form)
Nejprve si vytvoříme třídu MujFormular
, poté vytvoříme 3
políčka. U políček je prvním parametrem popisek, který můžeme zobrazit
pomocí Jinja2 šablon. Dále nastavíme inputům s číslem widget s typem
number
(stejné jako napsat
<input type="number">
) a SelectField
má jako
další argument pole, které obsahuje dvojice value
a
text
, které se zobrazí na stránce k výběru. Všimněte si
rozšíření konfigurace aplikace o ochranu proti podvrhnutí formuláře přes
útok CSRF.
Následně si vytvoříme instanci formuláře, který si automaticky vezme data z requestu. Poté zkontrolujeme, zda byl formulář odeslán a provedeme validaci dat. Pokud vše proběhlo úspěšně, data načteme a vrátíme výsledek.
Upravíme náš template a přidáme vygenerovaný formulář.
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <form method="POST"> {{ form.hidden_tag() }} {{ form.prvni_cislo }} {{ form.operator }} {{ form.druhe_cislo }} <input type="submit"> </form> <hr> Výsledek: {% if vysledek %} {{ vysledek }} {% else %} Vyplň formulář {% endif %} </body> </html>
Nejdříve vykreslíme všechny skryté tagy. Jelikož žádné nemáme, načte se pouze CSRF token, který našemu formuláři poskytuje ochranu proti podvržení. Poté načteme ostatní vstupní pole.
Aktuálně se nám budou ověřovat pouze číselná pole, pokud obsahují
číslo, a pole s operátorem, zda obsahuje jeden ze znaků /*-+
.
To nám nestačí a chceme vypsat i chybovou hlášku ke každému inputu. Kód
tedy ještě upravíme:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> </head> <body> <form method="POST"> {{ form.hidden_tag() }} {{ form.prvni_cislo }} {{ form.operator }} {{ form.druhe_cislo }} <input type="submit"> </form> {% for field, errors in form.errors.items() %} {% for error in errors %} <span style="color: red;">Chyba pole - {{ field }} hláška - {{ error }}</span><br> {% endfor %} {% endfor %} <hr> Výsledek: {% if vysledek %} {{ vysledek }} {% else %} Vyplň formulář {% endif %} </body> </html>
Chybová hláška vypadá takto:
Tvorba hlavní šablony
Bývá zvykem, že webová aplikace má nějakou hlavní šablonu (rozložení s navigačním menu, hlavičkou, patičkou a pozadím) a jednotlivé podstránky se poté vykreslují dovnitř. Pojďme tak učinit i u kalkulačky.
Nejprve si vytvoříme šablonu stránky. Pro náš účel stačí něco
jednoduchého, klidně si motiv poté upravte dle libosti. Vytvoříme si
šablonu base.html
, kterou vložíme do složky
root/templates/
. Kód bude mít následující:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Můj web ve Flasku</title> <style> html, body{ margin: 0; } #content{ margin: auto; max-width: 75%; min-height: 500%; border: solid; border-color: black; border-width: 2px; border-radius: 15px; padding: 100px; font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; } header{ min-height: 100px; min-width: 100%; background-color: #569ee2; margin-bottom: 50px; font-family: Arial Black; } footer{ position: absolute; bottom: 0; min-height: 120px; min-width: 100%; background-color: #569ee2; font-family: Arial Black; } </style> </head> <body> <header> {% block header %} Zde není nic zajímavého {% endblock %} </header> <div id="content"> {% block content %} {% endblock %} </div> <footer> {% block footer %} Prostý footer {% endblock %} </footer> </body> </html>
Všimněte si, že jsme si zde definovali bloky header
,
content
a footer
a do bloků header
a
footer
jsme vložili nějaký text. Ten se zobrazí na stránce
dědící z této šablony (tedy podstránce) pouze pokud blok nepoužijeme nebo
Jinja2 donutíme vyrenderovat obsah pomocí {{ super() }}
.
Vše je vidět z následující úpravy template.html
, který
nyní dědí z tohoto hlavního a vykresluje se tedy do něj. Obsahuje již jen
HTML kód potřebný pro danou podstránku s kalkulačkou a je kratší:
{% extends "base.html" %} {% block header %} Zde je něco zajímavého<br> {{ super() }} {% endblock %} {% block content %} <form method="POST"> {{ form.hidden_tag() }} <table> <tr><td>{{ form.prvni_cislo.label }}:</td><td>{{ form.prvni_cislo }}</td></tr> <tr><td>{{ form.operator.label }}: </td><td>{{ form.operator }}</td></tr> <tr><td>{{ form.druhe_cislo.label }}: </td><td>{{ form.druhe_cislo }}</td></tr> <tr><td></td><td><input type="submit" style="width: 100%;"></td></tr> </table> </form> {% for field, errors in form.errors.items() %} {% for error in errors %} <span style="color: red;">Chyba pole - {{ field }} hláška - {{ error }}</span><br> {% endfor %} {% endfor %} <hr> Výsledek: {% if vysledek %} {{ vysledek }} {% else %} Vyplň formulář {% endif %} {% endblock %}
Výsledek vypadá následovně, všimněte si headeru a footeru:
V příští lekci, Static files a upload souborů ve Flask, se podíváme na statické soubory a nahrávání.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 165x (1.75 kB)
Aplikace je včetně zdrojových kódů v jazyce Python