Python Lernhandbuch

Kapitel 15: Schöne Oberflächen ohne Design-Studium

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

Verbessere die Kundenverwaltung:

  1. Binde Pico.css und eigenes CSS ein und baue eine Navigationsleiste.
  2. Zeige Umsätze im deutschen Format mit euro-Filter, rechtsbündig.
  3. Baue die Live-Suche mit htmx: Beim Tippen im Suchfeld wird nach 300 ms nur der Tabellenkörper ersetzt.

Zuerst die Zeilen in ein eigenes Template templates/_zeilen.html auslagern (der Unterstrich kennzeichnet ein Teil-Template):

html
{% for k in kunden %}
<tr>
  <td>{{ k.name }}</td>
  <td>{{ k.stadt or '-' }}</td>
  <td class="zahl">{{ k.umsatz|euro }}</td>
  <td>
    <form method="post" action="/kunden/{{ k.id }}/loeschen">
      <button type="submit" class="secondary outline">Löschen</button>
    </form>
  </td>
</tr>
{% else %}
<tr><td colspan="4">Keine Kunden gefunden</td></tr>
{% endfor %}

In main.py die Abfrage in eine Funktion ziehen und zwei Routen daraus bedienen:

python
def lade_kunden(q):
    with pool.connection() as conn:
        return conn.execute(
            'SELECT id, name, stadt, umsatz FROM kunden WHERE name ILIKE %s ORDER BY name',
            (f'%{q}%',),
        ).fetchall()


@app.get('/', response_class=HTMLResponse)
def kundenliste(request: Request, q: str = ''):
    return templates.TemplateResponse(request, 'kunden.html', {'kunden': lade_kunden(q), 'q': q})


@app.get('/tabelle', response_class=HTMLResponse)
def tabelle(request: Request, q: str = ''):
    # liefert nur die Tabellenzeilen, für htmx
    return templates.TemplateResponse(request, '_zeilen.html', {'kunden': lade_kunden(q)})

In kunden.html steht das Suchfeld mit den hx--Attributen (siehe oben) und die Tabelle mit {% include '_zeilen.html' %}. Das Suchformular braucht keinen Absenden-Knopf mehr.

Was passiert:

  • Beim Tippen schickt htmx nach 300 ms Pause GET /tabelle?q=... (der Feldname q wird automatisch als Parameter angehängt). Die Antwort sind nur die <tr>-Zeilen, die in #tabelle eingesetzt werden. Die restliche Seite bleibt unverändert.
  • Dieselbe Vorlage _zeilen.html wird zweimal verwendet: bei der Gesamtseite und bei der Teilantwort. So gibt es genau eine Stelle für das Aussehen der Zeilen.
  • Der Filter euro sorgt für einheitliche Zahlen, und die CSS-Klasse zahl richtet sie rechts aus.
  • Pico gestaltet das alles ohne weitere Klassen. Es sind nur wenige Attribute nötig, weil Pico normales HTML direkt formatiert.

Warum so: Der Server liefert HTML-Bruchstücke, der Browser setzt sie ein: Du brauchst keine zweite Sprache und kein Frontend-Framework, und alle Logik bleibt in Python. Für Verwaltungsoberflächen, Tabellen und Formulare reicht dieser Ansatz sehr weit.