Python Schulung – Kursbezug
Merksatz: Flask = „Baukasten“ (viel Freiheit), Django = „Bausatz“ (viel drin, schneller standardisiert).
Worum geht’s?
- Flask vs. Django: Wann welches Framework?
- Grundbausteine: Routing, Request/Response, Templates, JSON.
- Typische Patterns: „Seiten“ + „API“ in einem Projekt.
- Minimaler Blick auf Deployment: WSGI/ASGI, Debug vs. Production.
Lehr-/Lernziele
- (LZ1) Flask und Django sinnvoll einordnen (Einsatzfälle, Trade-offs).
- (LZ2) Routing + Request/Response (HTML und JSON) implementieren.
- (LZ3) Templates/Rendering verstehen (Jinja in Flask, Templates in Django).
- (LZ4) Grundideen für Production-Betrieb erklären (Debug aus, WSGI/ASGI, Secrets/Config).
Flask vs. Django – Entscheidungshilfe
Flask (leichtgewichtig)
- Ideal für kleine Services, APIs, Prototypen
- Sie wählen Komponenten selbst (ORM, Auth, Admin …)
- Sehr gut zum Lernen von HTTP/Requests
Django (Full-Stack)
- Ideal für größere Apps mit Auth, Admin, ORM, Forms
- Viele Standards „out of the box“
- Schnell produktiv in Team/Projekt
Flask-Minimalbeispiel: Seite + JSON-API
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
# Beispiel-Daten (didaktisch)
kurse = [
{"id": 1, "kursname": "Python Schulung", "format": "Online", "standort": "Berlin", "preis_euro": 1390},
{"id": 2, "kursname": "Python Schulung", "format": "Praesenz", "standort": "Hamburg", "preis_euro": 1490},
]
@app.get("/")
def startseite():
return "<h1>SemaTrain – Python</h1><p>/kurse oder /api/kurse</p>"
@app.get("/kurse")
def kursseite():
# Template-Datei: templates/kurse.html
return render_template("kurse.html", kurse=kurse)
@app.get("/api/kurse")
def api_kurse():
# optionaler Filter: ?format=Online
format_filter = request.args.get("format")
daten = kurse
if format_filter:
daten = [k for k in kurse if k["format"] == format_filter]
return jsonify(daten)
if __name__ == "__main__":
app.run(debug=True)Template (Jinja): templates/kurse.html
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Kurse</title>
</head>
<body>
<h1>Kurse (Beispiel)</h1>
<ul>
{% for kurs in kurse %}
<li>
<strong>{{ kurs.kursname }}</strong> –
{{ kurs.format }} –
{{ kurs.standort }} –
{{ kurs.preis_euro }} €
</li>
{% endfor %}
</ul>
</body>
</html>Django-Minimalbeispiel: Model + View + URL
# app: kurse/models.py
from django.db import models
class Kurs(models.Model):
kursname = models.CharField(max_length=120)
format = models.CharField(max_length=30) # "Online" / "Praesenz"
standort = models.CharField(max_length=60)
dauer_tage = models.IntegerField()
preis_euro = models.DecimalField(max_digits=8, decimal_places=2)
def __str__(self) -> str:
return f"{self.kursname} ({self.format})"# app: kurse/views.py
from django.http import JsonResponse
from django.shortcuts import render
from .models import Kurs
def kursliste(request):
kurse = Kurs.objects.all().order_by("preis_euro")
return render(request, "kurse/kurse.html", {"kurse": kurse})
def api_kurse(request):
format_filter = request.GET.get("format")
qs = Kurs.objects.all()
if format_filter:
qs = qs.filter(format=format_filter)
daten = list(qs.values("id", "kursname", "format", "standort", "preis_euro"))
return JsonResponse(daten, safe=False)
# app: kurse/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("kurse/", views.kursliste, name="kursliste"),
path("api/kurse/", views.api_kurse, name="api_kurse"),
]Production-Grundidee: Debug aus + WSGI/ASGI
- (LZ4)
debug=Truenur lokal – in Production aus. - (LZ4) Webserver spricht nicht „Python direkt“, sondern startet App über WSGI/ASGI (z.B. Gunicorn/Uvicorn).
- (LZ4) Konfiguration/Secrets nicht hardcoden (ENV-Variablen).
Praxisaufgabe (Mini)
Sie bauen eine Mini-Web-App „Kursübersicht“: HTML + JSON-Endpoint.
Beitrag zu den Lehr-/Lernzielen: LZ1 (Framework-Wahl begründen), LZ2 (Routing/JSON), LZ3 (Template), LZ4 (Debug/Prod-Grundidee).
- (LZ1) Entscheiden: Flask oder Django? (Ein Satz Begründung: „Warum passt es hier?“)
- (LZ2) Route/URL
/api/kurse: gibt Kursliste als JSON aus, Filter?format=Online. - (LZ3) Route/URL
/kurse: rendert Template und zeigt Kurse an. - (Bonus) Detailseite
/kurse/<id>oder/kurse/<int:id>.
Lösungsvorschlag (Flask) anzeigen
from flask import Flask, jsonify, render_template_string, request, abort
app = Flask(__name__)
kurse = [
{"id": 1, "kursname": "Python Schulung", "format": "Online", "standort": "Berlin", "preis_euro": 1390},
{"id": 2, "kursname": "Python Schulung", "format": "Praesenz", "standort": "Hamburg", "preis_euro": 1490},
]
TEMPLATE = """
<h1>Kurse (Beispiel)</h1>
<ul>
{% for kurs in kurse %}
<li>
<a href="/kurse/{{ kurs.id }}">{{ kurs.kursname }}</a>
– {{ kurs.format }} – {{ kurs.standort }} – {{ kurs.preis_euro }} €
</li>
{% endfor %}
</ul>
"""
DETAIL = """
<h1>{{ kurs.kursname }}</h1>
<p>Format: {{ kurs.format }}</p>
<p>Standort: {{ kurs.standort }}</p>
<p>Preis: {{ kurs.preis_euro }} €</p>
<p><a href="/kurse">zurück</a></p>
"""
@app.get("/api/kurse")
def api_kurse():
format_filter = request.args.get("format")
daten = kurse if not format_filter else [k for k in kurse if k["format"] == format_filter]
return jsonify(daten)
@app.get("/kurse")
def kursliste():
return render_template_string(TEMPLATE, kurse=kurse)
@app.get("/kurse/<int:kurs_id>")
def kurs_detail(kurs_id: int):
kurs = next((k for k in kurse if k["id"] == kurs_id), None)
if kurs is None:
abort(404)
return render_template_string(DETAIL, kurs=kurs)
if __name__ == "__main__":
app.run(debug=True)Kurz-Takeaways
- LZ1: Flask = flexibel/leicht, Django = standardisiert/full-stack.
- LZ2: Routing liefert HTML oder JSON – gleiche Daten, andere Darstellung.
- LZ3: Templates trennen Logik und Darstellung (Jinja/Django Templates).
- LZ4: Debug nur lokal; Production über WSGI/ASGI + Konfiguration per ENV.