V Pythonu je možné vytvořit aplikace, které běží v prohlížeči, ačkoli způsob jejich implementace je trochu odlišný od JavaScriptu, protože Python není přirozeně podporován prohlížeči. Existují však nástroje a frameworky, které umožňují vytvořit webové aplikace pomocí Pythonu.
Použití webových frameworků (Back-end řešení)
Python se často používá na straně serveru, kde poskytuje API nebo generuje HTML stránky, které jsou následně vykreslovány v prohlížeči. K tomu slouží různé frameworky:
- Flask je jednoduchý a lehký framework pro malé aplikace.
- Django je robustní framework pro větší a složitější projekty.
- FastAPI je moderní framework vhodný pro tvorbu API s vysokým výkonem.
Jak to funguje:
- Python běží na serveru a generuje odpovědi na požadavky z prohlížeče (např. HTML stránky nebo data v JSON formátu).
- Front-end část aplikace může být psaná v HTML, CSS a JavaScriptu.
Příklad s Flaskem:
Nejdříve si ukážeme, jak spustit web appku napsanou v Pythonu lokálně z příkazové řádky Linuxu. Základní aplikace hello_flask.py
na kterou se po spuštění můžete připojit v prohlížeči http://localhost:5000
.
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return f"<h1>Vítej v Python aplikaci!</h1>"
if __name__ == '__main__':
app.run(debug=True)
Instalace Flasku
Modul Flask není součástí standardní knihovny Pythonu a je nutné jej nainstalovat ručně. V terminálu zadejte příkaz:
sudo apt install python3-flask
Tímto ověříte, že je Flask správně nainstalovaný.
python -m flask --version
Uložte hello_flask.py
například v editoru nano a spusťte.
nano hello_flask.py
python3 hello_flask.py
Zobrazí se:
* Serving Flask app 'hello_flask'
* Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on http://127.0.0.1:5000
Press CTRL+C to quit
* Restarting with stat
* Debugger is active!
* Debugger PIN: 134-689-662
127.0.0.1 - - [11/Jan/2025 12:54:14] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [11/Jan/2025 12:54:16] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [11/Jan/2025 12:54:22] "POST / HTTP/1.1" 200 -
Pokud budete potřebovat proces ukončit, zjistěte PID procesu běžícího na portu 5000
příkazem lsof
a ukončete příkazem kill
.
lsof -i :5000
sudo kill -9 3307715
Aplikaci hello_flask.py můžete rozšířit o formulář, který načte a vypíše vaše jméno.
from flask import Flask, render_template, request
app = Flask(__name__)
# Hlavní stránka s formulářem
@app.route('/', methods=['GET', 'POST'])
def home():
if request.method == 'POST':
# Získání jména z formuláře
name = request.form.get('name')
if name:
return f"<h1>Ahoj, {name}! Vítej v naší aplikaci.</h1>"
else:
return "<h1>Prosím, zadejte své jméno!</h1>"
return '''
<form method="post">
<label for="name">Zadej své jméno:</label>
<input type="text" id="name" name="name" placeholder="Vaše jméno">
<button type="submit">Odeslat</button>
</form>
'''
if __name__ == '__main__':
app.run(debug=True)
Po spuštění aplikace jste mohli zahlédnout varování:
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
Pokusím se ho vysvětlit…
Rozdíl mezi vývojovým serverem a produkčním WSGI serverem
- Vývojový server:
- Flask má zabudovaný vývojový server (běží pomocí
app.run()
). - Je navržen pouze pro lokální testování a vývoj.
- Není bezpečný ani výkonný pro nasazení na produkci.
- Flask má zabudovaný vývojový server (běží pomocí
- Produkční WSGI server:
- Servery jako Gunicorn, uWSGI nebo mod_wsgi jsou navrženy pro stabilitu, bezpečnost a vysoký výkon.
- Jsou optimalizované pro zpracování více požadavků současně a lépe integrují aplikace v Pythonu s tradičními webovými servery jako Nginx nebo Apache.
Proč Docker
Produkční WSGI server můžete samozřejmě naistalovat přímo. Proč to dělat složitější?
Kontejnerizace aplikací přináší mnoho výhod, ale pro mne jsou na domácím serveru největší přínosy bezpečnost a blbuvzdornost. Ty jsou dány izolací od ostatních aplikací a hostitelského systému. Pokud mi hacknou kontejner nebo ho ve slabší chvice rozvrtám sám, nepoloží to celý server. Kontejnery mohu snadno a rychle podle potřeb vypnout a uvolnit tak HW prostředky.
Instalace Dockeru
Zkušenosti mám jen s Debian a Alpine Linuxy. Nesetkal jsem se s žádnými problémy a mohu je doporučit i pro opravdu slabý HW. Instalaci Dockeru zvládne i nezkušený uživatel.
Debian Linux
sudo apt update && sudo apt install -y docker docker-compose
docker --version
systemctl status docker
Alpine Linux
apk add docker
rc-update add docker boot
service docker start
docker version
Portainer
Doporučuji začít kontejnerem Portainer-CE. Usnadňuje práci s kontejnery tím, že poskytuje webové intuitivní grafické uživatelské rozhraní (GUI), což znamená, že uživatelé mohou spravovat kontejnery, obrazy, sítě a svazky bez nutnosti používat příkazovou řádku.
docker volume create portainer_data
docker run -d -p 8000:8000 -p 9443:9443 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:2.21.5
Windows a macOS
Oficiální web docker.com nabízí pro Windows a Mac Docker Desktop. Nezkoušel jsem ho. Problém s instalací nejspíše nebude, ale Linux je pro Docker považován za nejlepší volbu z důvodů, které souvisejí s jeho nativním propojením s Linuxovým jádrem:
- Linuxové jádro obsahuje technologie jako cgroups a namespaces, které jsou základem pro fungování kontejnerů. Docker tyto funkce přímo využívá bez nutnosti emulace. Absence mezivrstvy zajišťuje minimální režii a vyšší výkon.
- Na Windows nebo macOS musí používat virtualizační vrstvy, jako je WSL2 nebo HyperKit, což přidává režijní náklady.
- Většina Docker obrazů je optimalizována pro Linux, protože servery v produkčním prostředí běží převážně na Linuxu.
- Řešení problémů a ladění je jednodušší díky dostupnosti nástrojů přímo v Linuxu, atd.
Vytvoření vlastního obrazu
Oficiální kontejner python:3.11-alpine na Docker Hub neobsahuje všechny potřebné knihovny. Mohli byste je doinstalovat po spuštění kontejneru, ale výhodné je využít automatizaci instalace a pomocí Dokerfile souboru vytvořit vlastní obraz.
Vytvořte si textový soubor bez přípony s názvem „Dockerfile“ a vložto do něj následující příkazy:
FROM python:3.11-alpine
# Instalace potřebných nástrojů pro kompilaci
RUN apk add --no-cache gcc python3-dev musl-dev linux-headers py3-pip
# Nastavení pracovní složky
WORKDIR /app
# Instalace Flasku, Gunicornu a psutilu
RUN pip install --no-cache-dir flask gunicorn psutil
# Kopírování aplikace
COPY . .
# Spuštění aplikace pomocí Gunicornu
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:app"]
Z adresáře se souborem „Dockerfile“ spusťte příkaz:
sudo docker build -t gunicorn:3.11-alpine . # Pozor na tečku
V případě jiného adresáře nahraďte tečku cestou k Dockerfile souboru. Parametr -t
je nepovinný. Umožňuje obraz pojmenovat.
Docker Compose
Vytvořit z obrazu kontejner lze i jinak, ale doporučuji vytvořit textový soubor „compose.yaml„. Slouží v Dockeru k definici a správě více kontejnerů jako jedné aplikace. Jedná se o konfigurační soubor v YAML formátu, který popisuje služby (kontejnery), jejich závislosti, síťová nastavení, svazky (volumes) a další parametry potřebné k jejich spuštění.
services:
web:
image: gunicorn:3.11-alpine # upravený obraz z Dockerfile
container_name: gunicorn
restart: unless-stopped
working_dir: /app
ports:
- "8001:8000" # číslo portu na levé straně můžete změnit
volumes:
- /home/admin/Workspace/Python/GunicornApp:/app
- /home/admin/Workspace/Python/GunicornApp/requirements.txt:/app/requirements.txt
command: >
sh -c "pip install --no-cache-dir -r requirements.txt &&
gunicorn -w 4 -b 0.0.0.0:8000 app:app"
Pomocí „requirements.txt“ výše můžete instalovat další balíčky.
Adresářovou strukturu /home/admin/Workspace/Python/GunicornApp si upravte podle sebe. Vložte soubory app.py
, compose.yaml
a případně requirements.txt
do vytvořeného adresáře. V příkazové řádce přejděte do adresáře, kde se nachází váš soubor compose.yaml
, a spusťte příkaz:
docker-compose up -d
-d
Spustí kontejnery na pozadí (detached mode).
Zkontrolujte, zda kontejnery běží správně:
docker ps
Pokud jste nezměnili port, měla by být vaše aplikace dostupná na http://localhost:8001
Pokud potřebujete upravit compose.yaml
, restartujte kontejnery příkazem:
docker-compose down && docker-compose up -d
Pokud chcete odstranit staré kontejnery a jejich data, použijte:
docker-compose down -v
Bonusový příklad
Vpravo vidíte reálné aktuální vytížení mého domácího serveru. Ve vaší web appce si toto zobrazení můžete také přidat. Pravidelný refresh provádí javascript. Statický obsah stránky je nyní umístěn v template souboru index.html.
from flask import Flask, render_template, request, jsonify
import psutil
app = Flask(__name__)
# Funkce pro získání údajů o systému
def get_usage():
cpu = psutil.cpu_percent()
mem = psutil.virtual_memory().percent
ssd = psutil.disk_usage('/').percent
return {
'cpu': f"{cpu}%",
'mem': f"{mem}%",
'ssd': f"{ssd}%",
}
@app.route('/', methods=['GET', 'POST'])
def home():
name = None
if request.method == 'POST':
name = request.form.get('name')
usage_data = get_usage()
return render_template('index.html', name=name, usage_data=usage_data)
@app.route('/refresh_usage')
def refresh_usage():
usage_data = get_usage()
return jsonify(usage_data)
if __name__ == '__main__':
app.run(debug=True)
Do adresáře s aplikací app.py
přidejte adresář /templates
a v něm vytvořte soubor index.html
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Monitorování systému</title>
<script>
// Funkce pro pravidelný refresh údajů
function fetchUsageData() {
fetch('/refresh_usage')
.then(response => response.json())
.then(data => {
document.getElementById('cpu').innerText = "CPU: " + data.cpu;
document.getElementById('mem').innerText = "Paměť: " + data.mem;
document.getElementById('ssd').innerText = "Disk: " + data.ssd;
});
}
// Automatický refresh každé 2 sekundy
setInterval(fetchUsageData, 2000);
</script>
</head>
<body>
<h1>Monitorování systému</h1>
<!-- Sekce pro zobrazení údajů o systému -->
<div id="system-monitor">
<p id="cpu">CPU: {{ usage_data['cpu'] }}</p>
<p id="mem">Paměť: {{ usage_data['mem'] }}</p>
<p id="ssd">Disk: {{ usage_data['ssd'] }}</p>
</div>
<!-- Sekce pro formulář -->
<div id="name-form">
<h2>Formulář</h2>
{% if name %}
<p>Ahoj, {{ name }}! Vítej v naší aplikaci.</p>
{% else %}
<form method="post">
<label for="name">Zadej své jméno:</label>
<input type="text" id="name" name="name" placeholder="Vaše jméno">
<button type="submit">Odeslat</button>
</form>
{% endif %}
</div>
</body>
</html>