2. Flask a frontend

Cíle cvičení

  1. seznámení s balíčkem (frameworkem) Flask
  2. vytvoření jednoduché statické stránky s vlastním HTML, CSS a JavaScript
  3. implementace knihovny Bootstrap

Důležité odkazy

Architektura MVC

Flask vychází z architektury nazývané Model-View-Controller (MVC). Tato architektura rozděluje aplikaci do tří hlavních částí - Model, View a Controller.

Programování pomocí knihoven grafického uživatelského rozhraní (GUI) usnadňuje implementaci MVC. MVC poprvé představil Trygve Reenskaug, vývojář jazyka Smalltalk ve výzkumném středisku Xerox Palo Alto Research Center v roce 1979, a pomáhá oddělit přístup k datům a pracovní logiku od způsobu, jakým jsou zobrazovány uživateli.

Modely

Model představuje data a pravidla, kterými se řídí přístup k těmto datům a jejich aktualizace. V komerčních softwarech model často slouží jako softwarová aproximace reálného procesu.

Modely by například mohly představovat struktury dat pro senzory, akční členy, nebo jiná zařízeni v IoT systému.

Views (Pohledy)

Pohledy vykreslují obsah modelu. Přesně určuje, jak mají být data modelu prezentována. Když se data modelu změní, musí zobrazení podle potřeby aktualizovat svou prezentaci. Toho lze dosáhnout použitím PUSH modelu, kdy se pohled sám registruje u modelu pro oznámení o změnách, nebo PULL modelu, kdy je pohled zodpovědný za volání modelu, když potřebuje získat nejaktuálnější data.

Controller (Kontrolér)

Kontrolér převádí interakce uživatele s pohledem na akce, které provede model. V samostatném klientovi s grafickým uživatelským rozhraním mohou interakce uživatele představovat kliknutí na tlačítko nebo výběr z nabídky, zatímco ve webových aplikacích se projevují jako požadavky HTTP GET a POST. V závislosti na kontextu může kontrolér také vybrat nové zobrazení (například webovou stránku s výsledky), které bude prezentovat zpět uživateli.

Flask a MVC

Flask, i když je často považován za součást MVC architektury, nemusí být považován za plnou implementaci této architektury. To je dáno tím, že Flask neobsahuje explicitní model složku, která je typická pro tradiční MVC architekturu.

V tradičním MVC model představuje data a pravidla, která řídí přístup k těmto datům a jejich aktualizace. Flask však neobsahuje takový model, což znamená, že data a logika aplikace jsou často smíchány, což může vést k nedostatečnému oddělení pracovní logiky a prezentační vrstvy.

Nicméně, Flask je často přirovnáván k MVC architektuře kvůli jeho flexibilitě a jednoduchosti. Flask umožňuje vývojářům snadno vytvářet webové aplikace bez nutnosti dodržovat striktní architektonické vzorce. To znamená, že vývojáři mohou vytvořit aplikaci, která má podobnou strukturu jako tradiční MVC aplikace, ale bez nutnosti dodržovat všechny aspekty MVC architektury.

Současný stav:

from flask import Flask  # Importing the Flask module from the flask package  
 
app = Flask(__name__)  # Creating an instance of the Flask class  
 
 
@app.route('/')  # View function for endpoint '/'  
def hello():  
    return "<h1>Hello, World!</h1>"  
 
 
# Starting a web application at 0.0.0.0.0:5000 with debug mode enabled  
if __name__ == "__main__":  
    app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=False)

Dále vytvoříme soubor requirements.txt který bude obsahovat seznam všech Python balíčků. Soubor můžeme vytvořit manuálně, nebo automaticky pomocí příkazu pip freeze > requirements.txt (viz první cvičení - Moduly a balíčky, Správa balíčků pomocí PIPu, Instalace balíčků pomocí requirements.txt).

Jako layout projektu zvolíme následující strukturu:

/home/user/Projects/flask-tutorial
├── app.py
├── templates/
│  └── index.html
├── static/
│  └── style.css
└── venv/

Static bude obsahovat statické soubory jako CSS a JavaScript. Templates bude obsahovat šablony HTML pro různé stránky aplikace.

Zobrazování HTML stránek

Aby naše funkce hello() pracovala s HTML, stačí ji změnit takto:

from flask import Flask  # Importing the Flask module from the flask package  
 
app = Flask(__name__)  # Creating an instance of the Flask class
 
@app.route('/')  # View function for endpoint '/'
def hello():
    return "<html><head><title>Hi there!</title></head><body>Hello, World!</body></html>", 200
 
# Starting a web application at 0.0.0.0.0:5000 with debug mode enabled  
if __name__ == "__main__":  
    app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=False)

V tomto případě hello() vrací řetězec ve formátu HTML a číslo. Řetězec bude ve výchozím nastavení analyzován jako HTML, zatímco 200 je nepovinný kód HTTP označující úspěšnou odpověď. Ve výchozím nastavení je vrácen kód 200.

Tento přístup k zobrazování HTML komponent je ovšem velmi limitující. Navíc definování HTML šablony uvnitř funkce, která zpracovává odpověď je z hlediska přístupu MVC nepřípustné.

app.py by z hlediska MVC architektury měl fungovat jako kontrolér. Pohledy budeme definovat pomocí HTML šablon uvnitř složky templates. Ve složce templates vytvoříme šablonu index.html:

<html lang="cs">  
<head>  
    <title>NSI App</title>  
</head>  
<body>Hello World!</body>  
</html>

A app.py upravíme následovně:

from flask import Flask, render_template  
 
app = Flask(__name__)  # Creating an instance of the Flask class  
 
@app.route('/')  # View function for endpoint '/'  
def hello():  
    return render_template('index.html')  
 
# Starting a web application at 0.0.0.0.0:5000 with debug mode enabled  
if __name__ == "__main__":  
    app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=False)

render_template umožňuje načítat šablony ze složky templates/ (výchozí pro Flask) a stačí je vykreslit pomocí vrácení výstupu.

Nyní přidáme několik JavaScript a CSS stylů. Vestavěný vývojový server Flask ve výchozím nastavení obsluhuje všechny soubory ve složce projektu, které se nacházejí v podsložce static. V této složce vytvoříme soubory styles.css a script.js

body {  
   display: flex;  
   justify-content: center;  
   align-items: center;  
   margin: 0;  
}  
 
h1 {  
   font-size: 2em;  
}

function getRandomColor() {  
    let letters = '0123456789ABCDEF';  
    let color = '#';  
    for (let i = 0; i < 6; i++) {  
        color += letters[Math.floor(Math.random() * 16)];  
    }  
    return color;  
}  
 
 let helloWorld = document.getElementById('hello-world');  
 helloWorld.style.color = getRandomColor();

Pro použití těchto souborů je ještě musíme zahrnout v index.html:

<html lang="cs">  
<head>  
    <title>NSI App</title>  
    <link rel="stylesheet" type="text/css" href="/static/styles.css">  
</head>  
<body>  
<h1 id="hello-world">Hello, World!</h1>  
<script src="/static/script.js"></script>  
</body>  
</html>

Knihovna Bootstrap

Pro použití dalších, složitějších grafických prvků je vhodné použít CSS knihovnu jako Bootstrap, Foundation, … CSS knihovna se v podstatě skládá z několika souborů CSS stylů připravených k použití vývojáři a návrháři webových stránek. Soubory stylů jsou připraveny pro standardní funkce webového designu: nastavení barev, rozvržení, písem, navigačních panelů atd. Obecně jsou soubory stylů podporovány a rozšiřovány o další skriptovací technologie, jako je SASS a JavaScript.

S CSS knihovnou má uživatel k dispozici hotový soubor stylů CSS a k vytvoření webové stránky mu stačí napsat HTML s přesnými třídami, strukturou a ID. Knihovna má již zabudované třídy pro běžné prvky webových stránek - zápatí, posuvník, navigační panel, rozvržení založené na sloupcích atd.

Import CSS Knihovny Bootstrap:

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">  
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" crossorigin="anonymous"></script>

Odkazy jsou dostupné z: Bootstrap · The most popular HTML, CSS, and JS library in the world. (getbootstrap.com)

<html lang="cs">  
<head>  
    <title>NSI app</title>  
    <link rel="stylesheet" type="text/css" href="/static/styles.css">  
 
    <!-- BOOTSTRAP https://getbootstrap.com/ -->  
    <link 
        href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" 
        rel="stylesheet" 
        integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" 
        crossorigin="anonymous">  
    <script 
        src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js" 
        integrity="sha384-C6RzsynM9kWDrMNeT87bh95OGNyZPhcTNXj1NW7RuBCsyN/o0jlpcV8Qyq46cDfL" 
        crossorigin="anonymous">
    </script>  
 
</head>  
<body>  
<nav class="navbar bg-body-tertiary">  
  <div class="container-fluid">  
    <a class="navbar-brand" href="#"><h1 id="hello-world">Hello, World!</h1></a>  
  </div>
</nav>  
 
<div class="card">  
  <div class="card-body">  
    Toto je text v těle karty.  
  </div>  
</div>  
 
<script src="/static/script.js"></script>  
</body>  
</html>

Šablony ve Flasku

Hlavní balíček, který se ve Flasku stará o pohledy - šablony je Jinja2 (Jinja — Documentation), pomocí kterého lze vytvářet formátovaný text s integrovanou logikou. Na rozdíl od funkce formátování v jazyce Python, která umožňuje pouze nahradit značky proměnným obsahem, lze uvnitř šablony řetězce mít řídicí strukturu, například for cyklus.

Šablona může obsahovat proměnné a výrazy, které se při vykreslení šablony nahradí hodnotami, které řídí logiku šablony. Syntaxe šablony je do značné míry inspirována jazykem Django a Python.

Existuje několik druhů oddělovačů. Výchozí oddělovače Jinja jsou nakonfigurovány takto:

  • {% ... %} - pro výrazy
  • {{ ... }} - pro výrazy, které se mají vypisovat na výstup šablony
  • {# ... #} - pro komentáře, které se do výstupu šablony nezahrnují.

Více informací: Template Designer Documentation — Jinja Documentation (3.0.x) (palletsprojects.com)

Oddělení dynamických části od statických

V naší webové aplikaci jsou komponenty, které se budou zobrazovat stejně na jakékoli URL - např. navbar. Místo definování navbaru v každé HTML Jinja šabloně můžeme využít dědičnost šablon. Ta umožňuje vytvořit základní “kostru” šablony, která obsahuje všechny společné prvky webu a definuje bloky, které mohou podřízené šablony přepisovat.

Proměnné v šablonách

Proměnné v šablonách jsou definovány kontextovým slovníkem předaným šabloně.

Zadání 1. miniprojektu

Navrhněte Flask aplikaci pro sledování teploty s pomocí knihovny Bootstrap a template enginu Jinja. Projekt vytvořte s pomocí virtuálního prostředí (viz cv01) a následně jej nahrajte na fakultní Gitlab. Do BRUTE následně nahrajte odkaz na tento repozitář, který bude mít nastavenou viditelnost buď internal nebo public.

  • V aplikaci budou existovat tři stránky: přihlašovací formulář, registrační formulář, dashboard.
  • Aplikace bude využívat dědičnost šablon pro navbar a tělo stránky.
  • V navbaru bude uveden: název stránky, název přihlášeného uživatele (zatím libovolný text, který se bude předávat šablon jako proměnná), tlačítko pro odhlášení.
  • Na stránce dashboard vytvořte layout z komponent knihovny Bootstrap. V layoutu musí být zohledněna oblast pro:
    • výpis poslední naměřené hodnoty s časem zápisu,
    • výpis tabulky X posledních naměřených hodnot s časem zápisu a ovládacím prvkem pro proměnnou X,
    • ovládací prvek pro smazání Y prvních (nejstarších) hodnot,
    • další komponenty dle vašeho uvážení (např. graf průběhu teploty v závislosti na čase, zobrazení počtu dat, apod.)
  • Naměřené hodnoty simulujte Python slovníkovým seznamem definovaným v serverové aplikaci (alespoň 5 záznamů {“timestamp”: value, “temp”: value}).
courses/b0b37nsi/tutorials/02.txt · Last modified: 2024/02/23 18:00 by spicajak