IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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:

Chybová hláška při validaci formulářů ve WTForms ve Flask frameworku v Pythonu - Flask framework pro Python

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:

Flask framework pro Python

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 154x (1.75 kB)
Aplikace je včetně zdrojových kódů v jazyce Python

 

Předchozí článek
Seznámení s Flask microframeworkem
Všechny články v sekci
Flask framework pro Python
Přeskočit článek
(nedoporučujeme)
Static files a upload souborů ve Flask
Článek pro vás napsal MQ .
Avatar
Uživatelské hodnocení:
39 hlasů
Používám hlavně Python a zajímám se o Deep Learning a vše kolem.
Aktivity