CherryPy: Čeresnička medzi veľkými titánmi
CherryPy: Čeresnička medzi veľkými titánmi
"Malý, ale mocný - niekedy najlepšie veci prichádzajú v malom balení" 🍒
Python web framework aréna je ako Avengers film. Máte tam Django (Iron Man - má všetko), FastAPI (Spider-Man - mladý, rýchly), Flask (Captain America - obľúbenec všetkých).
A potom je tu CherryPy - Ant-Man. Malý, podceňovaný, ale keď ho potrebujete, je perfektný.
Prológ: Aréna frameworkov
# 2025 Python Web Framework Summit
Django: "Mám admin panel, ORM, autentifikáciu, šablóny..."
FastAPI: "Som async, rýchly, moderný, automatická dokumentácia..."
Flask: "Som flexibilný, populárny, 54K GitHub hviezdičiek..."
CherryPy: "Mám... vstavaný HTTP server?"
Všetci: *trápne ticho*
CherryPy: "A tiež dokážem čokoľvek v 10 riadkoch kódu?"
Developer v rohu: "Ukáž mi to."
*o 5 minút neskôr*
Developer: "Do riti, toto je presne to čo potrebujem!"
CherryPy: "Hovoril som. Som čerešnička na torte." 🍒Kapitola 1: Titáni
Titán #1: Django (Kolos)
Filozofia "batérie v cene"
# Django jednoduché API
# Štruktúra súborov:
# myproject/
# myapp/
# models.py
# views.py
# urls.py
# serializers.py
# admin.py
# apps.py
# tests.py
# myproject/
# settings.py
# urls.py
# wsgi.py
# models.py
from django.db import models
class User(models.Model):
name = models.CharField(max_length=100)
email = models.EmailField(unique=True)
# views.py
from django.http import JsonResponse
from .models import User
def get_users(request):
users = User.objects.all().values()
return JsonResponse(list(users), safe=False)
# urls.py (app level)
from django.urls import path
from . import views
urlpatterns = [
path('users/', views.get_users),
]
# urls.py (project level)
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('myapp.urls')),
]
# settings.py (200+ riadkov konfigurácie)
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
# ... 190 ďalších riadkov
]
# Celkovo: 7 súborov, 300+ riadkov
# Čas na setup: 30 minút
# Ideálne pre: Enterprise aplikácieVýhody:
- Všetko v balení
- Admin panel zadarmo
- Skvelé pre veľké projekty
Nevýhody:
- Prehnané pre jednoduché API
- Strmá krivka učenia
- Ťažkopádne
Titán #2: FastAPI (Rýchlik)
Filozofia "moderný, rýchly, async"
# FastAPI jednoduché API
# main.py
from fastapi import FastAPI
from pydantic import BaseModel
from typing import List
app = FastAPI()
class User(BaseModel):
id: int
name: str
email: str
users_db = [
User(id=1, name="John", email="john@example.com"),
User(id=2, name="Jane", email="jane@example.com")
]
@app.get("/users", response_model=List[User])
async def get_users():
return users_db
# Spustiť s: uvicorn main:app --reload
# Celkovo: 1 súbor, 25 riadkov
# Čas na setup: 5 minút
# Auto-generovaná OpenAPI dokumentácia na /docs
# Ideálne pre: Moderné APIVýhody:
- Super rýchly
- Async podpora
- Auto dokumentácia
- Type hints
Nevýhody:
- Vyžaduje Python 3.7+
- Menší ekosystém
- Potrebuje externý server (uvicorn)
Titán #3: Flask (Populárny frajer)
Filozofia "micro-framework"
# Flask jednoduché API
# app.py
from flask import Flask, jsonify, request
app = Flask(__name__)
users = [
{"id": 1, "name": "John", "email": "john@example.com"},
{"id": 2, "name": "Jane", "email": "jane@example.com"}
]
@app.route('/users', methods=['GET'])
def get_users():
return jsonify(users)
@app.route('/users/<int:user_id>', methods=['GET'])
def get_user(user_id):
user = next((u for u in users if u['id'] == user_id), None)
return jsonify(user) if user else ('Not found', 404)
if __name__ == '__main__':
app.run(debug=True)
# Celkovo: 1 súbor, 25 riadkov
# Čas na setup: 5 minút
# Spustiť s: python app.py
# Ideálne pre: VšetkoVýhody:
- Najpopulárnejší
- Obrovský ekosystém
- Výborná dokumentácia
- Ľahké na naučenie
Nevýhody:
- Potrebuje externý server pre produkciu
- Nie je async by default
- Môže sa stať chaotickým na veľkých projektoch
Kapitola 2: Prichádza čerešnička 🍒
CherryPy: Outsider
Filozofia "objektovo-orientovaný, minimalistický, sebestačný"
# CherryPy jednoduché API
# server.py
import cherrypy
import json
class UserAPI:
def __init__(self):
self.users = [
{"id": 1, "name": "John", "email": "john@example.com"},
{"id": 2, "name": "Jane", "email": "jane@example.com"}
]
@cherrypy.expose
@cherrypy.tools.json_out()
def index(self):
"""GET /users"""
return self.users
@cherrypy.expose
@cherrypy.tools.json_out()
def show(self, id):
"""GET /users/123"""
user = next((u for u in self.users if u['id'] == int(id)), None)
if not user:
raise cherrypy.HTTPError(404, "User not found")
return user
if __name__ == '__main__':
cherrypy.quickstart(UserAPI(), '/users')
# Celkovo: 1 súbor, 30 riadkov
# Čas na setup: 5 minút
# Spustiť s: python server.py
# Vstavaný produkčný server! ✨Počkať, čo?
Developer: "Kde je konfigurácia externého servera?"
CherryPy: "Vstavaná."
Developer: "Kde je WSGI konfig?"
CherryPy: "Nepotrebuješ."
Developer: "A čo produkcia?"
CherryPy: "Rovnaký príkaz. Je to production-ready."
Developer: "..."
CherryPy: "😎"Kapitola 3: Tajná omáčka
Funkcia #1: Vstavaný HTTP server
Ostatné frameworky:
# Flask produkcia
pip install gunicorn
gunicorn app:app
# FastAPI produkcia
pip install uvicorn
uvicorn main:app
# Django produkcia
pip install gunicorn
gunicorn myproject.wsgi
# Všetky potrebujú externý server!CherryPy:
# Vývoj
python server.py
# Produkcia
python server.py
# To je všetko. Rovnaký príkaz. 🎉Prečo je to dôležité:
# Scenár rýchleho testovania:
# 10:00 - Potrebujem otestovať API
# 10:01 - Napíšem CherryPy API
# 10:05 - python server.py
# 10:06 - Testujem!
# vs Flask:
# 10:00 - Potrebujem otestovať API
# 10:01 - Napíšem Flask API
# 10:05 - Inštalujem gunicorn
# 10:07 - Konfigurujem gunicorn
# 10:10 - Riešim problémy s gunicornom
# 10:15 - Konečne testujem!
# Víťaz: CherryPy (o 10 minút)Funkcia #2: Objektovo-orientované API
CherryPy prirodzená štruktúra:
import cherrypy
class Root:
@cherrypy.expose
def index(self):
return "Domov"
class UsersAPI:
@cherrypy.expose
def index(self):
return "Zoznam užívateľov"
@cherrypy.expose
def show(self, id):
return f"Užívateľ {id}"
class ProductsAPI:
@cherrypy.expose
def index(self):
return "Zoznam produktov"
# Mount štruktúra
root = Root()
root.users = UsersAPI()
root.products = ProductsAPI()
cherrypy.quickstart(root, '/')
# URL automaticky:
# / → Root.index()
# /users → UsersAPI.index()
# /users/show/123 → UsersAPI.show(id=123)
# /products → ProductsAPI.index()
# Intuitívne! Prirodzené! Pythonické! 🐍Funkcia #3: Jednoduchosť konfigurácie
CherryPy konfig:
import cherrypy
config = {
'global': {
'server.socket_host': '0.0.0.0',
'server.socket_port': 8080,
'server.thread_pool': 10
},
'/': {
'tools.sessions.on': True,
'tools.auth.on': True
}
}
cherrypy.quickstart(MyApp(), '/', config)
# Jednoduchý slovník!
# Ľahko pochopiteľné!
# Ľahko modifikovateľné!Django konfig:
# settings.py (200 riadkov)
ALLOWED_HOSTS = []
INSTALLED_APPS = [...]
MIDDLEWARE = [...]
# ... 180 ďalších riadkov
# Zložité!
# Krivka učenia!
# Kde je konfigurácia socketu?!Kapitola 4: Rýchly štart z reálneho sveta
Scenár: Potrebujem API za 5 minút
Misia:
12:00 - Manager: "Vieš rýchlo spraviť testovacie API?"
12:05 - Manager: "Potrebujem to ukázať na meetingu!"
Panika: ZAPNUTÁ 😰Riešenie: CherryPy zachraňuje situáciu!
# test_api.py (napísané za 3 minúty)
import cherrypy
from datetime import datetime
class QuickAPI:
@cherrypy.expose
@cherrypy.tools.json_out()
def index(self):
"""GET / - Info o API"""
return {
"name": "Quick Test API",
"version": "1.0",
"status": "running",
"timestamp": datetime.now().isoformat()
}
@cherrypy.expose
@cherrypy.tools.json_out()
def users(self):
"""GET /users"""
return [
{"id": 1, "name": "Alice", "active": True},
{"id": 2, "name": "Bob", "active": False},
{"id": 3, "name": "Charlie", "active": True}
]
@cherrypy.expose
@cherrypy.tools.json_out()
def stats(self):
"""GET /stats"""
return {
"total_users": 3,
"active_users": 2,
"uptime": "5 minút",
"requests": 42
}
if __name__ == '__main__':
cherrypy.config.update({
'server.socket_host': '0.0.0.0',
'server.socket_port': 8080,
'log.screen': False
})
cherrypy.quickstart(QuickAPI(), '/')
# Celkový čas: 3 minútySpustenie:
python test_api.py
# CherryPy beží na http://0.0.0.0:8080Testovanie:
curl http://localhost:8080/
curl http://localhost:8080/users
curl http://localhost:8080/stats
# Všetko funguje! ✅
# Čas: 5 minút
# Manager: "Perfektné! Ukaž to!"
# Ty: 😎Kapitola 5: Pokročilé rýchle recepty
Recept #1: REST API s CRUD
import cherrypy
class TaskAPI:
def __init__(self):
self.tasks = {
1: {"id": 1, "title": "Naučiť sa CherryPy", "done": True},
2: {"id": 2, "title": "Postaviť API", "done": False}
}
self.next_id = 3
@cherrypy.expose
@cherrypy.tools.json_out()
def index(self):
"""GET /tasks - Zoznam všetkých"""
return list(self.tasks.values())
@cherrypy.expose
@cherrypy.tools.json_out()
def show(self, id):
"""GET /tasks/show/1 - Získať jednu"""
task = self.tasks.get(int(id))
if not task:
raise cherrypy.HTTPError(404, "Úloha nenájdená")
return task
@cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out()
def create(self):
"""POST /tasks/create"""
data = cherrypy.request.json
task = {
"id": self.next_id,
"title": data["title"],
"done": data.get("done", False)
}
self.tasks[self.next_id] = task
self.next_id += 1
return task
@cherrypy.expose
@cherrypy.tools.json_in()
@cherrypy.tools.json_out()
def update(self, id):
"""PUT /tasks/update/1"""
task_id = int(id)
if task_id not in self.tasks:
raise cherrypy.HTTPError(404, "Úloha nenájdená")
data = cherrypy.request.json
self.tasks[task_id].update(data)
return self.tasks[task_id]
@cherrypy.expose
@cherrypy.tools.json_out()
def delete(self, id):
"""DELETE /tasks/delete/1"""
task_id = int(id)
if task_id not in self.tasks:
raise cherrypy.HTTPError(404, "Úloha nenájdená")
del self.tasks[task_id]
return {"message": "Úloha vymazaná"}
if __name__ == '__main__':
cherrypy.quickstart(TaskAPI(), '/tasks')
# Kompletné CRUD API v 50 riadkoch!Recept #2: Statické súbory + API
import cherrypy
import os
class WebApp:
@cherrypy.expose
def index(self):
"""Servírovať HTML stránku"""
return open('index.html').read()
class API:
@cherrypy.expose
@cherrypy.tools.json_out()
def data(self):
"""GET /api/data"""
return {"message": "Ahoj z API"}
if __name__ == '__main__':
config = {
'/': {
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.abspath('static'),
'tools.staticdir.index': 'index.html'
}
}
root = WebApp()
root.api = API()
cherrypy.quickstart(root, '/', config)
# Servíruje:
# / → index.html
# /static/style.css → CSS
# /api/data → JSON
# Full-stack v jednom súbore! 🚀Recept #3: Autentifikácia
import cherrypy
from functools import wraps
# Jednoduchý auth dekorátor
def require_auth(f):
@wraps(f)
def wrapper(*args, **kwargs):
auth = cherrypy.request.headers.get('Authorization')
if auth != 'Bearer secret-token':
raise cherrypy.HTTPError(401, "Neautorizované")
return f(*args, **kwargs)
return wrapper
class ProtectedAPI:
@cherrypy.expose
@cherrypy.tools.json_out()
def public(self):
"""GET /public - Bez autentifikácie"""
return {"message": "Verejný endpoint"}
@cherrypy.expose
@cherrypy.tools.json_out()
@require_auth
def private(self):
"""GET /private - Vyžaduje autentifikáciu"""
return {"message": "Tajné dáta", "user": "autentifikovaný"}
if __name__ == '__main__':
cherrypy.quickstart(ProtectedAPI(), '/')
# Autentifikácia v 20 riadkoch!Kapitola 6: Porovnávacia matica
CherryPy vs Titáni
| Funkcia | Django | FastAPI | Flask | CherryPy | Víťaz |
|---|---|---|---|---|---|
| Čas setupu | 30 min | 5 min | 5 min | 5 min | 🤝 Remíza |
| Vstavaný server | Nie | Nie | Len dev | ✅ Produkcia | 🏆 CherryPy |
| Riadky kódu | 300+ | 25 | 25 | 30 | 🤝 Remíza |
| Production ready | Áno | Treba uvicorn | Treba gunicorn | ✅ Vstavané | 🏆 CherryPy |
| Krivka učenia | Strmá | Stredná | Ľahká | Ľahká | 🤝 Flask/CherryPy |
| Popularita | 🔥🔥🔥 | 🔥🔥 | 🔥🔥🔥 | 🔥 | 🏆 Django/Flask |
| Ekosystém | Obrovský | Rastúci | Obrovský | Malý | 🏆 Django |
| OOP priateľský | Stredne | Nie | Nie | ✅ Veľmi | 🏆 CherryPy |
| Async podpora | Áno | ✅ Natívne | Nie | Plugin | 🏆 FastAPI |
| Auto dokumentácia | Admin | ✅ OpenAPI | Nie | Nie | 🏆 FastAPI |
| Rýchle prototypy | Nie | Áno | Áno | ✅ Perfektné | 🏆 CherryPy |
| Enterprise appky | ✅ Perfektné | Áno | Áno | Stredne | 🏆 Django |
Kedy čo použiť?
def vyber_framework(projekt):
if projekt.typ == "Enterprise" and projekt.potrebuje_admin:
return "Django" # Full-stack kolos
if projekt.typ == "Moderné API" and projekt.potrebuje_vykon:
return "FastAPI" # Rýchlik
if projekt.typ == "Čokoľvek" and projekt.popularita_je_dolezita:
return "Flask" # Bezpečná voľba
if projekt.typ == "Rýchly test" or projekt.typ == "Prototyp":
return "CherryPy" # Tajná zbraň 🍒
if projekt.potrebuje == "Vstavaný server" and projekt.jednoduchosť:
return "CherryPy" # Skrytý klenotKapitola 7: Skryté klenoty
Klenot #1: Konfigurácia thread poolu
import cherrypy
cherrypy.config.update({
'server.thread_pool': 30, # Zvládne 30 súbežných požiadaviek
'server.thread_pool_max': 50 # Maximum 50 vlákien
})
# Jednoduchá kontrola vlákien!
# Žiadna externá konfigurácia!Klenot #2: Viaceré inštancie servera
from cherrypy import _cpserver
# Server 1: Verejné API
server1 = _cpserver.Server()
server1.socket_port = 8080
server1.subscribe()
# Server 2: Admin API
server2 = _cpserver.Server()
server2.socket_port = 8081
server2.subscribe()
cherrypy.tree.mount(PublicAPI(), '/', config1)
cherrypy.tree.mount(AdminAPI(), '/', config2)
cherrypy.engine.start()
cherrypy.engine.block()
# Dva servery, jeden proces! 🚀Klenot #3: Request hooky
import cherrypy
from datetime import datetime
def log_request():
"""Zaloguj každú požiadavku"""
print(f"[{datetime.now()}] {cherrypy.request.method} {cherrypy.request.path_info}")
def add_cors():
"""Pridaj CORS hlavičky"""
cherrypy.response.headers['Access-Control-Allow-Origin'] = '*'
# Registruj hooky
cherrypy.tools.log_request = cherrypy.Tool('before_handler', log_request)
cherrypy.tools.cors = cherrypy.Tool('before_finalize', add_cors)
config = {
'/': {
'tools.log_request.on': True,
'tools.cors.on': True
}
}
# Middleware jednoducho!Kapitola 8: Reálne prípady použitia
Prípad #1: Rýchle prototypovanie
Situácia: Klient chce vidieť API demo zajtra
Časová os:
- 9:00 - Získam požiadavky
- 10:00 - Začnem kódovať s CherryPy
- 10:30 - Základné API hotové
- 11:00 - Pridám nejaké funkcie
- 11:30 - Test a doladenie
- 12:00 - Deploy (ten istý python súbor!)
- 14:00 - Demo pre klienta
Výsledok: ✅ Klient ohromený
Nástroj: CherryPy (perfektný na toto!)
Alternatíva s Django:
- 9:00 - Získam požiadavky
- 10:00 - Nastavujem Django projekt
- 11:00 - Stále konfigurujem...
- 12:00 - Prvý endpoint funguje
- 14:00 - Demo odložené na zajtra
Víťaz: CherryPyPrípad #2: Mock server pre testovanie
# Mock API pre testovanie
import cherrypy
import random
class MockAPI:
@cherrypy.expose
@cherrypy.tools.json_out()
def users(self):
"""Mock users endpoint"""
return [
{"id": i, "name": f"Užívateľ {i}"}
for i in range(1, 11)
]
@cherrypy.expose
@cherrypy.tools.json_out()
def random_delay(self):
"""Simuluj pomalý endpoint"""
import time
time.sleep(random.uniform(1, 3))
return {"status": "pomalá odpoveď"}
@cherrypy.expose
def error(self):
"""Simuluj chybu"""
raise cherrypy.HTTPError(500, "Simulovaná chyba")
if __name__ == '__main__':
cherrypy.quickstart(MockAPI(), '/mock')
# Perfektné pre:
# - Frontend vývoj (pred tým než je backend hotový)
# - Integračné testovanie
# - Záťažové testovanie
# - Testovanie chybových scenárovPrípad #3: Interné nástroje
# Firemné interné API
import cherrypy
import sqlite3
class InternalTools:
def __init__(self):
self.db = sqlite3.connect('company.db', check_same_thread=False)
@cherrypy.expose
@cherrypy.tools.json_out()
def employees(self):
"""GET /employees"""
cursor = self.db.execute('SELECT * FROM employees')
return [dict(row) for row in cursor.fetchall()]
@cherrypy.expose
@cherrypy.tools.json_out()
def stats(self):
"""GET /stats"""
cursor = self.db.execute('SELECT COUNT(*) FROM employees')
return {"total_employees": cursor.fetchone()[0]}
if __name__ == '__main__':
cherrypy.config.update({
'server.socket_host': '192.168.1.100', # Interná IP
'server.socket_port': 8080
})
cherrypy.quickstart(InternalTools(), '/')
# Perfektné pre interné firemné nástroje!Kapitola 9: Obmedzenia (čas na úprimnosť)
Obmedzenie #1: Menšia komunita
GitHub hviezdy:
- Flask: 67K ⭐
- Django: 79K ⭐
- FastAPI: 75K ⭐
- CherryPy: 1.8K ⭐
Realita - menej:
- StackOverflow odpovedí
- Pluginov tretích strán
- Tutoriálových videí
- Blogových článkov
Dopad:
- Ťažšie nájsť pomoc
- Menej hotových riešení
- Viac práce sám
Riešenie:
- Dobré pre skúsených developerov
- Prečítajte (dobrú) dokumentáciu
- Komunita je malá ale nápomocnáObmedzenie #2: Nie je "trendy"
Pracovné ponuky:
"Požadované: Django ALEBO Flask ALEBO FastAPI"
"Výhodou: FastAPI skúsenosti"
"Musí vedieť: Flask"
CherryPy: *nespomenuté*
Realita:
- Nepomôže vášmu CV
- Menej predajná zručnosť
- Niche nástroj
Ale:
- Perfektný pre osobné projekty
- Skvelý pre rýchle prototypy
- Výborný pre interné nástroje
- Skrytá zbraň v toolboxe 🔧Obmedzenie #3: Nie je async (defaultne)
# ❌ Nie je natívne async
class API:
@cherrypy.expose
def endpoint(self):
# Len synchrónne
result = slow_operation()
return result
# vs FastAPI
@app.get("/endpoint")
async def endpoint():
# Async!
result = await slow_operation()
return result
# CherryPy môže použiť gevent, ale nie je to také elegantnéEpilóg: Perfektný čerešničkový moment
Kedy CherryPy žiari:
situacie = {
"rychly_prototyp": True, # ⭐ Najlepšia voľba
"mock_server": True, # ⭐ Najlepšia voľba
"interne_nastroje": True, # ⭐ Najlepšia voľba
"ucebny_projekt": True, # ⭐ Skvelá voľba
"microservice": True, # ⭐ Dobrá voľba
"testovacie_api": True, # ⭐ Perfektná voľba
"enterprise_app": False, # ❌ Použi Django
"vysoko_vykonne_api": False, # ❌ Použi FastAPI
"trendy_cv_skill": False, # ❌ Použi Flask
"async_heavy": False # ❌ Použi FastAPI
}
verdikt = """
CherryPy nie je najlepší framework na všetko.
Ale pre rýchle prototypy, interné nástroje a testovanie?
Je to TAJNÁ ZBRAŇ. 🍒
Malý, rýchly, sebestačný, production-ready.
Žiadny externý server.
Žiadna zložitá konfigurácia.
Len čisté Python OOP.
Čerešnička na torte? Naozaj to funguje. 😎
"""Záver: Prijmite čerešničku
Záverečný verdikt:
if potrebujes == "rychle_a_spinavy":
return cherrypy # Najrýchlejšia cesta k výsledku
if potrebujes == "production_grade":
return django # Batérie v cene
if potrebujes == "moderny_vykon":
return fastapi # Rýchlik
if potrebujes == "popularny_a_bezpecny":
return flask # Komunitný favorit
if potrebujes == "vstavany_server":
return cherrypy # Jediný! 🍒
# Pridajte CherryPy do svojho toolboxu
# Neskôr mi poďakujeteMoje odporúčanie:
Váš arzenál frameworkov:
1. Django - Tank (enterprise)
2. FastAPI - Športiak (výkon)
3. Flask - Sedan (spoľahlivý denný vodič)
4. CherryPy - Motorka (rýchla, obratná) 🏍️
Použite správny nástroj na správnu úlohu.
CherryPy je podceňovaný.
Nespite na ňom.Pravda:
Je CherryPy najlepší framework? Nie.
Je najpopulárnejší? Nie.
Je najrýchlejší? Nie.
Pomôže vám získať prácu? Asi nie.
Ale môže vám ušetriť hodiny v piatok popoludní
keď potrebujete rýchle API na testovanie?
ROZHODNE. 🍒
A niekedy je to presne to, čo potrebujete.Článok napísal developer, ktorý používa Django pre produkciu, FastAPI pre výkon, Flask pre popularitu, a CherryPy pre "potrebujem to rozbehnúť za 5 minút" momenty.
Stack: CherryPy 18.8+, Python 3.7+, vstavaný HTTP server (MVP).
Odporúčanie: Naučte sa CherryPy. Nie ako hlavný framework, ale ako tajnú zbraň v toolboxe. Keď budete potrebovať rýchly prototyp alebo mock server, oceníte to.
P.S.: Popularita ≠ Kvalita. Niekedy je outsider perfektný na danú úlohu. CherryPy je ten outsider. 🍒
P.P.S.: Vstavaný produkčný server je game changer. Žiadny gunicorn, žiadny uvicorn, žiadny nginx. Len python server.py. Vyskúšajte to. Uvidíte. 😊