Python Lernhandbuch

Kapitel 14: Webapplikation mit FastAPI und Jinja2

Musterlösung mit Erklärung

Vergleiche Schritt für Schritt mit deinem Programm in VS Code. Wenn alles passt, markiere die Übung als erledigt.
Aufgabe noch einmal lesen

Erweitere die Kundenverwaltung:

  1. In jeder Tabellenzeile gibt es einen Löschen-Button (POST an /kunden/{id}/loeschen), danach geht es zurück zur Liste.
  2. Unter der Tabelle steht die Summe aller Umsätze.
  3. Ein neuer JSON-Endpunkt GET /api/umsatz-pro-stadt liefert eine Liste mit stadt und umsatz.

Neue Routen in main.py:

python
@app.post('/kunden/{kunden_id}/loeschen')
def kunde_loeschen(kunden_id: int):
    with pool.connection() as conn:
        conn.execute('DELETE FROM kunden WHERE id = %s', (kunden_id,))
    return RedirectResponse('/', status_code=303)


@app.get('/api/umsatz-pro-stadt')
def umsatz_pro_stadt():
    with pool.connection() as conn:
        return conn.execute('''
            SELECT COALESCE(stadt, 'unbekannt') AS stadt, SUM(umsatz) AS umsatz
            FROM kunden
            GROUP BY stadt
            ORDER BY umsatz DESC
        ''').fetchall()

In kundenliste die Summe berechnen und ans Template geben:

python
    gesamt = sum(k['umsatz'] for k in kunden)
    return templates.TemplateResponse(
        request, 'kunden.html', {'kunden': kunden, 'q': q, 'gesamt': gesamt}
    )

In kunden.html die Löschen-Spalte und die Summenzeile:

html
      <td>
        <form method="post" action="/kunden/{{ k.id }}/loeschen">
          <button type="submit">Löschen</button>
        </form>
      </td>
html
  <tfoot>
    <tr><th colspan="3">Summe</th><th>{{ '%.2f'|format(gesamt) }}</th></tr>
  </tfoot>

(Die Kopfzeile bekommt eine fünfte leere Spalte, und in der Summenzeile wird colspan entsprechend angepasst.)

Was passiert:

  • Browser-Formulare können nur GET und POST. Deshalb löschst du über ein kleines Formular mit POST, nicht mit DELETE.
  • {kunden_id} im Pfad wird als int erkannt und kommt fertig umgewandelt in der Funktion an.
  • COALESCE(stadt, 'unbekannt') ersetzt NULL im SQL durch einen Text. GROUP BY und SUM übernimmt die Datenbank.
  • Die Summe in Python (sum(...)) nutzt die bereits geladenen Zeilen: Die Summe passt damit zur Suche, die gerade angezeigt wird.

Warum so: Die Trennung in drei Schichten macht die Anwendung leicht änderbar: Routen (was passiert bei einer Anfrage), Datenbank (woher kommen die Daten) und Templates (wie sieht es aus). Dieselben Daten kannst du als HTML-Seite (für Menschen) und als JSON (für andere Programme) anbieten.