====== 2. Flask a frontend ====== ===== Cíle cvičení ===== - seznámení s balíčkem (frameworkem) Flask - vytvoření jednoduché statické stránky s vlastním HTML, CSS a JavaScript - implementace knihovny Bootstrap ===== Důležité odkazy ===== * [[https://gitlab.fel.cvut.cz/spicajak/navrh-systemu-iot/-/tree/main/lecture-02|Gitlab - podklady pro Cvičení 2]] * [[https://www.w3schools.com|W3Schools - základy HTML, CSS, JavaScrip (a mnoho dalšího)]] * [[https://flask.palletsprojects.com/en/3.0.x/|Dokumentace Flask]] * [[https://jinja.palletsprojects.com/en/3.0.x/|Dokumentace Jinja]] * [[https://getbootstrap.com|Knihovna Bootstrap]] ===== Návod ke cvičení ===== ==== 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 "

Hello, World!

" # 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 "Hi there!Hello, World!", 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%%'': NSI App Hello World! 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%%'': NSI App

Hello, World!

==== 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: Odkazy jsou dostupné z: [[https://getbootstrap.com/|Bootstrap · The most popular HTML, CSS, and JS library in the world. (getbootstrap.com)]] NSI app
Toto je text v těle karty.
==== Šablony ve Flasku ==== Hlavní balíček, který se ve Flasku stará o pohledy - šablony je Jinja2 ([[https://jinja.palletsprojects.com/en/3.1.x/|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í: [[https://jinja.palletsprojects.com/en/3.0.x/templates/#list-of-control-structures|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 [[https://gitlab.fel.cvut.cz|fakultní Gitlab]]. Do [[https://cw.felk.cvut.cz/brute|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 [[https://jinja.palletsprojects.com/en/3.0.x/templates/#template-inheritance|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 [[https://pythonexamples.org/python-list-of-dictionaries/|Python slovníkovým seznamem]] definovaným v serverové aplikaci (alespoň 5 záznamů ''{"timestamp": value, "temp": value}'').